4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 Roo.log('start render...');
313 Roo.log(this[cntr](true));
315 if(this[cntr](true) === false){
316 Roo.log(['skip', cn]);
320 cn.render && cn.render(this[cntr](true));
323 // then add the element..
331 if (typeof (tree.menu) != 'undefined') {
332 tree.menu.parentType = cn.xtype;
333 tree.menu.triggerEl = cn.el;
334 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
338 if (!tree.items || !tree.items.length) {
340 //Roo.log(["no children", this]);
345 var items = tree.items;
348 //Roo.log(items.length);
350 if (!skip_children) {
351 for(var i =0;i < items.length;i++) {
352 // Roo.log(['add child', items[i]]);
353 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
359 //Roo.log("fire childrenrendered");
361 cn.fireEvent('childrenrendered', this);
366 * Show a component - removes 'hidden' class
371 this.el.removeClass('hidden');
375 * Hide a component - adds 'hidden' class
379 if (this.el && !this.el.hasClass('hidden')) {
380 this.el.addClass('hidden');
393 * @class Roo.bootstrap.Body
394 * @extends Roo.bootstrap.Component
395 * Bootstrap Body class
399 * @param {Object} config The config object
402 Roo.bootstrap.Body = function(config){
404 config = config || {};
406 Roo.bootstrap.Body.superclass.constructor.call(this, config);
407 this.el = Roo.get(config.el ? config.el : document.body );
408 if (this.cls && this.cls.length) {
409 Roo.get(document.body).addClass(this.cls);
413 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
415 is_body : true,// just to make sure it's constructed?
420 onRender : function(ct, position)
422 /* Roo.log("Roo.bootstrap.Body - onRender");
423 if (this.cls && this.cls.length) {
424 Roo.get(document.body).addClass(this.cls);
443 * @class Roo.bootstrap.ButtonGroup
444 * @extends Roo.bootstrap.Component
445 * Bootstrap ButtonGroup class
446 * @cfg {String} size lg | sm | xs (default empty normal)
447 * @cfg {String} align vertical | justified (default none)
448 * @cfg {String} direction up | down (default down)
449 * @cfg {Boolean} toolbar false | true
450 * @cfg {Boolean} btn true | false
455 * @param {Object} config The config object
458 Roo.bootstrap.ButtonGroup = function(config){
459 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
462 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
470 getAutoCreate : function(){
476 cfg.html = this.html || cfg.html;
487 if (['vertical','justified'].indexOf(this.align)!==-1) {
488 cfg.cls = 'btn-group-' + this.align;
490 if (this.align == 'justified') {
491 console.log(this.items);
495 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
496 cfg.cls += ' btn-group-' + this.size;
499 if (this.direction == 'up') {
500 cfg.cls += ' dropup' ;
516 * @class Roo.bootstrap.Button
517 * @extends Roo.bootstrap.Component
518 * Bootstrap Button class
519 * @cfg {String} html The button content
520 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
521 * @cfg {String} size ( lg | sm | xs)
522 * @cfg {String} tag ( a | input | submit)
523 * @cfg {String} href empty or href
524 * @cfg {Boolean} disabled default false;
525 * @cfg {Boolean} isClose default false;
526 * @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)
527 * @cfg {String} badge text for badge
528 * @cfg {String} theme default
529 * @cfg {Boolean} inverse
530 * @cfg {Boolean} toggle
531 * @cfg {String} ontext text for on toggle state
532 * @cfg {String} offtext text for off toggle state
533 * @cfg {Boolean} defaulton
534 * @cfg {Boolean} preventDefault default true
535 * @cfg {Boolean} removeClass remove the standard class..
536 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
539 * Create a new button
540 * @param {Object} config The config object
544 Roo.bootstrap.Button = function(config){
545 Roo.bootstrap.Button.superclass.constructor.call(this, config);
546 this.weightClass = ["btn-default",
558 * When a butotn is pressed
559 * @param {Roo.bootstrap.Button} this
560 * @param {Roo.EventObject} e
565 * After the button has been toggles
566 * @param {Roo.EventObject} e
567 * @param {boolean} pressed (also available as button.pressed)
573 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
591 preventDefault: true,
600 getAutoCreate : function(){
608 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
609 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
614 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
616 if (this.toggle == true) {
619 cls: 'slider-frame roo-button',
624 'data-off-text':'OFF',
625 cls: 'slider-button',
631 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
632 cfg.cls += ' '+this.weight;
641 cfg["aria-hidden"] = true;
643 cfg.html = "×";
649 if (this.theme==='default') {
650 cfg.cls = 'btn roo-button';
652 //if (this.parentType != 'Navbar') {
653 this.weight = this.weight.length ? this.weight : 'default';
655 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
657 cfg.cls += ' btn-' + this.weight;
659 } else if (this.theme==='glow') {
662 cfg.cls = 'btn-glow roo-button';
664 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
666 cfg.cls += ' ' + this.weight;
672 this.cls += ' inverse';
677 cfg.cls += ' active';
681 cfg.disabled = 'disabled';
685 Roo.log('changing to ul' );
687 this.glyphicon = 'caret';
690 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
692 //gsRoo.log(this.parentType);
693 if (this.parentType === 'Navbar' && !this.parent().bar) {
694 Roo.log('changing to li?');
703 href : this.href || '#'
706 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
707 cfg.cls += ' dropdown';
714 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
716 if (this.glyphicon) {
717 cfg.html = ' ' + cfg.html;
722 cls: 'glyphicon glyphicon-' + this.glyphicon
732 // cfg.cls='btn roo-button';
736 var value = cfg.html;
741 cls: 'glyphicon glyphicon-' + this.glyphicon,
760 cfg.cls += ' dropdown';
761 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
764 if (cfg.tag !== 'a' && this.href !== '') {
765 throw "Tag must be a to set href.";
766 } else if (this.href.length > 0) {
767 cfg.href = this.href;
770 if(this.removeClass){
775 cfg.target = this.target;
780 initEvents: function() {
781 // Roo.log('init events?');
782 // Roo.log(this.el.dom);
785 if (typeof (this.menu) != 'undefined') {
786 this.menu.parentType = this.xtype;
787 this.menu.triggerEl = this.el;
788 this.addxtype(Roo.apply({}, this.menu));
792 if (this.el.hasClass('roo-button')) {
793 this.el.on('click', this.onClick, this);
795 this.el.select('.roo-button').on('click', this.onClick, this);
798 if(this.removeClass){
799 this.el.on('click', this.onClick, this);
802 this.el.enableDisplayMode();
805 onClick : function(e)
812 Roo.log('button on click ');
813 if(this.preventDefault){
816 if (this.pressed === true || this.pressed === false) {
817 this.pressed = !this.pressed;
818 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
819 this.fireEvent('toggle', this, e, this.pressed);
823 this.fireEvent('click', this, e);
827 * Enables this button
831 this.disabled = false;
832 this.el.removeClass('disabled');
836 * Disable this button
840 this.disabled = true;
841 this.el.addClass('disabled');
844 * sets the active state on/off,
845 * @param {Boolean} state (optional) Force a particular state
847 setActive : function(v) {
849 this.el[v ? 'addClass' : 'removeClass']('active');
852 * toggles the current active state
854 toggleActive : function()
856 var active = this.el.hasClass('active');
857 this.setActive(!active);
861 setText : function(str)
863 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
867 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
878 setWeight : function(str)
880 this.el.removeClass(this.weightClass);
881 this.el.addClass('btn-' + str);
895 * @class Roo.bootstrap.Column
896 * @extends Roo.bootstrap.Component
897 * Bootstrap Column class
898 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
899 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
900 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
901 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
902 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
903 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
904 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
905 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
908 * @cfg {Boolean} hidden (true|false) hide the element
909 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
910 * @cfg {String} fa (ban|check|...) font awesome icon
911 * @cfg {Number} fasize (1|2|....) font awsome size
913 * @cfg {String} icon (info-sign|check|...) glyphicon name
915 * @cfg {String} html content of column.
918 * Create a new Column
919 * @param {Object} config The config object
922 Roo.bootstrap.Column = function(config){
923 Roo.bootstrap.Column.superclass.constructor.call(this, config);
926 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
944 getAutoCreate : function(){
945 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
953 ['xs','sm','md','lg'].map(function(size){
954 //Roo.log( size + ':' + settings[size]);
956 if (settings[size+'off'] !== false) {
957 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
960 if (settings[size] === false) {
964 if (!settings[size]) { // 0 = hidden
965 cfg.cls += ' hidden-' + size;
968 cfg.cls += ' col-' + size + '-' + settings[size];
973 cfg.cls += ' hidden';
976 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
977 cfg.cls +=' alert alert-' + this.alert;
981 if (this.html.length) {
982 cfg.html = this.html;
986 if (this.fasize > 1) {
987 fasize = ' fa-' + this.fasize + 'x';
989 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
994 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1013 * @class Roo.bootstrap.Container
1014 * @extends Roo.bootstrap.Component
1015 * Bootstrap Container class
1016 * @cfg {Boolean} jumbotron is it a jumbotron element
1017 * @cfg {String} html content of element
1018 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1019 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1020 * @cfg {String} header content of header (for panel)
1021 * @cfg {String} footer content of footer (for panel)
1022 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1023 * @cfg {String} tag (header|aside|section) type of HTML tag.
1024 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1025 * @cfg {String} fa font awesome icon
1026 * @cfg {String} icon (info-sign|check|...) glyphicon name
1027 * @cfg {Boolean} hidden (true|false) hide the element
1028 * @cfg {Boolean} expandable (true|false) default false
1029 * @cfg {Boolean} expanded (true|false) default true
1030 * @cfg {String} rheader contet on the right of header
1031 * @cfg {Boolean} clickable (true|false) default false
1035 * Create a new Container
1036 * @param {Object} config The config object
1039 Roo.bootstrap.Container = function(config){
1040 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1046 * After the panel has been expand
1048 * @param {Roo.bootstrap.Container} this
1053 * After the panel has been collapsed
1055 * @param {Roo.bootstrap.Container} this
1060 * When a element is chick
1061 * @param {Roo.bootstrap.Container} this
1062 * @param {Roo.EventObject} e
1068 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1086 getChildContainer : function() {
1092 if (this.panel.length) {
1093 return this.el.select('.panel-body',true).first();
1100 getAutoCreate : function(){
1103 tag : this.tag || 'div',
1107 if (this.jumbotron) {
1108 cfg.cls = 'jumbotron';
1113 // - this is applied by the parent..
1115 // cfg.cls = this.cls + '';
1118 if (this.sticky.length) {
1120 var bd = Roo.get(document.body);
1121 if (!bd.hasClass('bootstrap-sticky')) {
1122 bd.addClass('bootstrap-sticky');
1123 Roo.select('html',true).setStyle('height', '100%');
1126 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1130 if (this.well.length) {
1131 switch (this.well) {
1134 cfg.cls +=' well well-' +this.well;
1143 cfg.cls += ' hidden';
1147 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1148 cfg.cls +=' alert alert-' + this.alert;
1153 if (this.panel.length) {
1154 cfg.cls += ' panel panel-' + this.panel;
1156 if (this.header.length) {
1160 if(this.expandable){
1162 cfg.cls = cfg.cls + ' expandable';
1166 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1174 cls : 'panel-title',
1175 html : (this.expandable ? ' ' : '') + this.header
1179 cls: 'panel-header-right',
1185 cls : 'panel-heading',
1186 style : this.expandable ? 'cursor: pointer' : '',
1194 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1199 if (this.footer.length) {
1201 cls : 'panel-footer',
1210 body.html = this.html || cfg.html;
1211 // prefix with the icons..
1213 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1216 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1221 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1222 cfg.cls = 'container';
1228 initEvents: function()
1230 if(this.expandable){
1231 var headerEl = this.headerEl();
1234 headerEl.on('click', this.onToggleClick, this);
1239 this.el.on('click', this.onClick, this);
1244 onToggleClick : function()
1246 var headerEl = this.headerEl();
1262 if(this.fireEvent('expand', this)) {
1264 this.expanded = true;
1266 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1268 this.el.select('.panel-body',true).first().removeClass('hide');
1270 var toggleEl = this.toggleEl();
1276 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1281 collapse : function()
1283 if(this.fireEvent('collapse', this)) {
1285 this.expanded = false;
1287 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1288 this.el.select('.panel-body',true).first().addClass('hide');
1290 var toggleEl = this.toggleEl();
1296 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1300 toggleEl : function()
1302 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1306 return this.el.select('.panel-heading .fa',true).first();
1309 headerEl : function()
1311 if(!this.el || !this.panel.length || !this.header.length){
1315 return this.el.select('.panel-heading',true).first()
1320 if(!this.el || !this.panel.length){
1324 return this.el.select('.panel-body',true).first()
1327 titleEl : function()
1329 if(!this.el || !this.panel.length || !this.header.length){
1333 return this.el.select('.panel-title',true).first();
1336 setTitle : function(v)
1338 var titleEl = this.titleEl();
1344 titleEl.dom.innerHTML = v;
1347 getTitle : function()
1350 var titleEl = this.titleEl();
1356 return titleEl.dom.innerHTML;
1359 setRightTitle : function(v)
1361 var t = this.el.select('.panel-header-right',true).first();
1367 t.dom.innerHTML = v;
1370 onClick : function(e)
1374 this.fireEvent('click', this, e);
1388 * @class Roo.bootstrap.Img
1389 * @extends Roo.bootstrap.Component
1390 * Bootstrap Img class
1391 * @cfg {Boolean} imgResponsive false | true
1392 * @cfg {String} border rounded | circle | thumbnail
1393 * @cfg {String} src image source
1394 * @cfg {String} alt image alternative text
1395 * @cfg {String} href a tag href
1396 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1397 * @cfg {String} xsUrl xs image source
1398 * @cfg {String} smUrl sm image source
1399 * @cfg {String} mdUrl md image source
1400 * @cfg {String} lgUrl lg image source
1403 * Create a new Input
1404 * @param {Object} config The config object
1407 Roo.bootstrap.Img = function(config){
1408 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1414 * The img click event for the img.
1415 * @param {Roo.EventObject} e
1421 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1423 imgResponsive: true,
1433 getAutoCreate : function()
1435 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1436 return this.createSingleImg();
1441 cls: 'roo-image-responsive-group',
1446 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1448 if(!_this[size + 'Url']){
1454 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1455 html: _this.html || cfg.html,
1456 src: _this[size + 'Url']
1459 img.cls += ' roo-image-responsive-' + size;
1461 var s = ['xs', 'sm', 'md', 'lg'];
1463 s.splice(s.indexOf(size), 1);
1465 Roo.each(s, function(ss){
1466 img.cls += ' hidden-' + ss;
1469 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1470 cfg.cls += ' img-' + _this.border;
1474 cfg.alt = _this.alt;
1487 a.target = _this.target;
1491 cfg.cn.push((_this.href) ? a : img);
1498 createSingleImg : function()
1502 cls: (this.imgResponsive) ? 'img-responsive' : '',
1504 src : 'about:blank' // just incase src get's set to undefined?!?
1507 cfg.html = this.html || cfg.html;
1509 cfg.src = this.src || cfg.src;
1511 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1512 cfg.cls += ' img-' + this.border;
1529 a.target = this.target;
1534 return (this.href) ? a : cfg;
1537 initEvents: function()
1540 this.el.on('click', this.onClick, this);
1545 onClick : function(e)
1547 Roo.log('img onclick');
1548 this.fireEvent('click', this, e);
1551 * Sets the url of the image - used to update it
1552 * @param {String} url the url of the image
1555 setSrc : function(url)
1559 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1560 this.el.dom.src = url;
1564 this.el.select('img', true).first().dom.src = url;
1580 * @class Roo.bootstrap.Link
1581 * @extends Roo.bootstrap.Component
1582 * Bootstrap Link Class
1583 * @cfg {String} alt image alternative text
1584 * @cfg {String} href a tag href
1585 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1586 * @cfg {String} html the content of the link.
1587 * @cfg {String} anchor name for the anchor link
1588 * @cfg {String} fa - favicon
1590 * @cfg {Boolean} preventDefault (true | false) default false
1594 * Create a new Input
1595 * @param {Object} config The config object
1598 Roo.bootstrap.Link = function(config){
1599 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1605 * The img click event for the img.
1606 * @param {Roo.EventObject} e
1612 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1616 preventDefault: false,
1622 getAutoCreate : function()
1624 var html = this.html || '';
1626 if (this.fa !== false) {
1627 html = '<i class="fa fa-' + this.fa + '"></i>';
1632 // anchor's do not require html/href...
1633 if (this.anchor === false) {
1635 cfg.href = this.href || '#';
1637 cfg.name = this.anchor;
1638 if (this.html !== false || this.fa !== false) {
1641 if (this.href !== false) {
1642 cfg.href = this.href;
1646 if(this.alt !== false){
1651 if(this.target !== false) {
1652 cfg.target = this.target;
1658 initEvents: function() {
1660 if(!this.href || this.preventDefault){
1661 this.el.on('click', this.onClick, this);
1665 onClick : function(e)
1667 if(this.preventDefault){
1670 //Roo.log('img onclick');
1671 this.fireEvent('click', this, e);
1684 * @class Roo.bootstrap.Header
1685 * @extends Roo.bootstrap.Component
1686 * Bootstrap Header class
1687 * @cfg {String} html content of header
1688 * @cfg {Number} level (1|2|3|4|5|6) default 1
1691 * Create a new Header
1692 * @param {Object} config The config object
1696 Roo.bootstrap.Header = function(config){
1697 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1700 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1708 getAutoCreate : function(){
1713 tag: 'h' + (1 *this.level),
1714 html: this.html || ''
1726 * Ext JS Library 1.1.1
1727 * Copyright(c) 2006-2007, Ext JS, LLC.
1729 * Originally Released Under LGPL - original licence link has changed is not relivant.
1732 * <script type="text/javascript">
1736 * @class Roo.bootstrap.MenuMgr
1737 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1740 Roo.bootstrap.MenuMgr = function(){
1741 var menus, active, groups = {}, attached = false, lastShow = new Date();
1743 // private - called when first menu is created
1746 active = new Roo.util.MixedCollection();
1747 Roo.get(document).addKeyListener(27, function(){
1748 if(active.length > 0){
1756 if(active && active.length > 0){
1757 var c = active.clone();
1767 if(active.length < 1){
1768 Roo.get(document).un("mouseup", onMouseDown);
1776 var last = active.last();
1777 lastShow = new Date();
1780 Roo.get(document).on("mouseup", onMouseDown);
1785 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1786 m.parentMenu.activeChild = m;
1787 }else if(last && last.isVisible()){
1788 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1793 function onBeforeHide(m){
1795 m.activeChild.hide();
1797 if(m.autoHideTimer){
1798 clearTimeout(m.autoHideTimer);
1799 delete m.autoHideTimer;
1804 function onBeforeShow(m){
1805 var pm = m.parentMenu;
1806 if(!pm && !m.allowOtherMenus){
1808 }else if(pm && pm.activeChild && active != m){
1809 pm.activeChild.hide();
1813 // private this should really trigger on mouseup..
1814 function onMouseDown(e){
1815 Roo.log("on Mouse Up");
1817 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1818 Roo.log("MenuManager hideAll");
1827 function onBeforeCheck(mi, state){
1829 var g = groups[mi.group];
1830 for(var i = 0, l = g.length; i < l; i++){
1832 g[i].setChecked(false);
1841 * Hides all menus that are currently visible
1843 hideAll : function(){
1848 register : function(menu){
1852 menus[menu.id] = menu;
1853 menu.on("beforehide", onBeforeHide);
1854 menu.on("hide", onHide);
1855 menu.on("beforeshow", onBeforeShow);
1856 menu.on("show", onShow);
1858 if(g && menu.events["checkchange"]){
1862 groups[g].push(menu);
1863 menu.on("checkchange", onCheck);
1868 * Returns a {@link Roo.menu.Menu} object
1869 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1870 * be used to generate and return a new Menu instance.
1872 get : function(menu){
1873 if(typeof menu == "string"){ // menu id
1875 }else if(menu.events){ // menu instance
1878 /*else if(typeof menu.length == 'number'){ // array of menu items?
1879 return new Roo.bootstrap.Menu({items:menu});
1880 }else{ // otherwise, must be a config
1881 return new Roo.bootstrap.Menu(menu);
1888 unregister : function(menu){
1889 delete menus[menu.id];
1890 menu.un("beforehide", onBeforeHide);
1891 menu.un("hide", onHide);
1892 menu.un("beforeshow", onBeforeShow);
1893 menu.un("show", onShow);
1895 if(g && menu.events["checkchange"]){
1896 groups[g].remove(menu);
1897 menu.un("checkchange", onCheck);
1902 registerCheckable : function(menuItem){
1903 var g = menuItem.group;
1908 groups[g].push(menuItem);
1909 menuItem.on("beforecheckchange", onBeforeCheck);
1914 unregisterCheckable : function(menuItem){
1915 var g = menuItem.group;
1917 groups[g].remove(menuItem);
1918 menuItem.un("beforecheckchange", onBeforeCheck);
1930 * @class Roo.bootstrap.Menu
1931 * @extends Roo.bootstrap.Component
1932 * Bootstrap Menu class - container for MenuItems
1933 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1934 * @cfg {bool} hidden if the menu should be hidden when rendered.
1935 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1936 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1940 * @param {Object} config The config object
1944 Roo.bootstrap.Menu = function(config){
1945 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1946 if (this.registerMenu && this.type != 'treeview') {
1947 Roo.bootstrap.MenuMgr.register(this);
1952 * Fires before this menu is displayed
1953 * @param {Roo.menu.Menu} this
1958 * Fires before this menu is hidden
1959 * @param {Roo.menu.Menu} this
1964 * Fires after this menu is displayed
1965 * @param {Roo.menu.Menu} this
1970 * Fires after this menu is hidden
1971 * @param {Roo.menu.Menu} this
1976 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1977 * @param {Roo.menu.Menu} this
1978 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1979 * @param {Roo.EventObject} e
1984 * Fires when the mouse is hovering over this menu
1985 * @param {Roo.menu.Menu} this
1986 * @param {Roo.EventObject} e
1987 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1992 * Fires when the mouse exits this menu
1993 * @param {Roo.menu.Menu} this
1994 * @param {Roo.EventObject} e
1995 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2000 * Fires when a menu item contained in this menu is clicked
2001 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2002 * @param {Roo.EventObject} e
2006 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2009 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2013 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2016 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2018 registerMenu : true,
2020 menuItems :false, // stores the menu items..
2030 getChildContainer : function() {
2034 getAutoCreate : function(){
2036 //if (['right'].indexOf(this.align)!==-1) {
2037 // cfg.cn[1].cls += ' pull-right'
2043 cls : 'dropdown-menu' ,
2044 style : 'z-index:1000'
2048 if (this.type === 'submenu') {
2049 cfg.cls = 'submenu active';
2051 if (this.type === 'treeview') {
2052 cfg.cls = 'treeview-menu';
2057 initEvents : function() {
2059 // Roo.log("ADD event");
2060 // Roo.log(this.triggerEl.dom);
2062 this.triggerEl.on('click', this.onTriggerClick, this);
2064 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2066 this.triggerEl.addClass('dropdown-toggle');
2069 this.el.on('touchstart' , this.onTouch, this);
2071 this.el.on('click' , this.onClick, this);
2073 this.el.on("mouseover", this.onMouseOver, this);
2074 this.el.on("mouseout", this.onMouseOut, this);
2078 findTargetItem : function(e)
2080 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2084 //Roo.log(t); Roo.log(t.id);
2086 //Roo.log(this.menuitems);
2087 return this.menuitems.get(t.id);
2089 //return this.items.get(t.menuItemId);
2095 onTouch : function(e)
2097 Roo.log("menu.onTouch");
2098 //e.stopEvent(); this make the user popdown broken
2102 onClick : function(e)
2104 Roo.log("menu.onClick");
2106 var t = this.findTargetItem(e);
2107 if(!t || t.isContainer){
2112 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2113 if(t == this.activeItem && t.shouldDeactivate(e)){
2114 this.activeItem.deactivate();
2115 delete this.activeItem;
2119 this.setActiveItem(t, true);
2127 Roo.log('pass click event');
2131 this.fireEvent("click", this, t, e);
2135 if(!t.href.length || t.href == '#'){
2136 (function() { _this.hide(); }).defer(100);
2141 onMouseOver : function(e){
2142 var t = this.findTargetItem(e);
2145 // if(t.canActivate && !t.disabled){
2146 // this.setActiveItem(t, true);
2150 this.fireEvent("mouseover", this, e, t);
2152 isVisible : function(){
2153 return !this.hidden;
2155 onMouseOut : function(e){
2156 var t = this.findTargetItem(e);
2159 // if(t == this.activeItem && t.shouldDeactivate(e)){
2160 // this.activeItem.deactivate();
2161 // delete this.activeItem;
2164 this.fireEvent("mouseout", this, e, t);
2169 * Displays this menu relative to another element
2170 * @param {String/HTMLElement/Roo.Element} element The element to align to
2171 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2172 * the element (defaults to this.defaultAlign)
2173 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2175 show : function(el, pos, parentMenu){
2176 this.parentMenu = parentMenu;
2180 this.fireEvent("beforeshow", this);
2181 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2184 * Displays this menu at a specific xy position
2185 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2186 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2188 showAt : function(xy, parentMenu, /* private: */_e){
2189 this.parentMenu = parentMenu;
2194 this.fireEvent("beforeshow", this);
2195 //xy = this.el.adjustForConstraints(xy);
2199 this.hideMenuItems();
2200 this.hidden = false;
2201 this.triggerEl.addClass('open');
2203 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2204 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2207 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2212 this.fireEvent("show", this);
2218 this.doFocus.defer(50, this);
2222 doFocus : function(){
2224 this.focusEl.focus();
2229 * Hides this menu and optionally all parent menus
2230 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2232 hide : function(deep)
2235 this.hideMenuItems();
2236 if(this.el && this.isVisible()){
2237 this.fireEvent("beforehide", this);
2238 if(this.activeItem){
2239 this.activeItem.deactivate();
2240 this.activeItem = null;
2242 this.triggerEl.removeClass('open');;
2244 this.fireEvent("hide", this);
2246 if(deep === true && this.parentMenu){
2247 this.parentMenu.hide(true);
2251 onTriggerClick : function(e)
2253 Roo.log('trigger click');
2255 var target = e.getTarget();
2257 Roo.log(target.nodeName.toLowerCase());
2259 if(target.nodeName.toLowerCase() === 'i'){
2265 onTriggerPress : function(e)
2267 Roo.log('trigger press');
2268 //Roo.log(e.getTarget());
2269 // Roo.log(this.triggerEl.dom);
2271 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2272 var pel = Roo.get(e.getTarget());
2273 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2274 Roo.log('is treeview or dropdown?');
2278 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2282 if (this.isVisible()) {
2287 this.show(this.triggerEl, false, false);
2290 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2297 hideMenuItems : function()
2299 Roo.log("hide Menu Items");
2303 //$(backdrop).remove()
2304 this.el.select('.open',true).each(function(aa) {
2306 aa.removeClass('open');
2307 //var parent = getParent($(this))
2308 //var relatedTarget = { relatedTarget: this }
2310 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2311 //if (e.isDefaultPrevented()) return
2312 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2315 addxtypeChild : function (tree, cntr) {
2316 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2318 this.menuitems.add(comp);
2339 * @class Roo.bootstrap.MenuItem
2340 * @extends Roo.bootstrap.Component
2341 * Bootstrap MenuItem class
2342 * @cfg {String} html the menu label
2343 * @cfg {String} href the link
2344 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2345 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2346 * @cfg {Boolean} active used on sidebars to highlight active itesm
2347 * @cfg {String} fa favicon to show on left of menu item.
2348 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2352 * Create a new MenuItem
2353 * @param {Object} config The config object
2357 Roo.bootstrap.MenuItem = function(config){
2358 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2363 * The raw click event for the entire grid.
2364 * @param {Roo.bootstrap.MenuItem} this
2365 * @param {Roo.EventObject} e
2371 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2375 preventDefault: false,
2376 isContainer : false,
2380 getAutoCreate : function(){
2382 if(this.isContainer){
2385 cls: 'dropdown-menu-item'
2399 if (this.fa !== false) {
2402 cls : 'fa fa-' + this.fa
2411 cls: 'dropdown-menu-item',
2414 if (this.parent().type == 'treeview') {
2415 cfg.cls = 'treeview-menu';
2418 cfg.cls += ' active';
2423 anc.href = this.href || cfg.cn[0].href ;
2424 ctag.html = this.html || cfg.cn[0].html ;
2428 initEvents: function()
2430 if (this.parent().type == 'treeview') {
2431 this.el.select('a').on('click', this.onClick, this);
2435 this.menu.parentType = this.xtype;
2436 this.menu.triggerEl = this.el;
2437 this.menu = this.addxtype(Roo.apply({}, this.menu));
2441 onClick : function(e)
2443 Roo.log('item on click ');
2445 if(this.preventDefault){
2448 //this.parent().hideMenuItems();
2450 this.fireEvent('click', this, e);
2469 * @class Roo.bootstrap.MenuSeparator
2470 * @extends Roo.bootstrap.Component
2471 * Bootstrap MenuSeparator class
2474 * Create a new MenuItem
2475 * @param {Object} config The config object
2479 Roo.bootstrap.MenuSeparator = function(config){
2480 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2483 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2485 getAutoCreate : function(){
2504 * @class Roo.bootstrap.Modal
2505 * @extends Roo.bootstrap.Component
2506 * Bootstrap Modal class
2507 * @cfg {String} title Title of dialog
2508 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2509 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2510 * @cfg {Boolean} specificTitle default false
2511 * @cfg {Array} buttons Array of buttons or standard button set..
2512 * @cfg {String} buttonPosition (left|right|center) default right
2513 * @cfg {Boolean} animate default true
2514 * @cfg {Boolean} allow_close default true
2515 * @cfg {Boolean} fitwindow default false
2516 * @cfg {String} size (sm|lg) default empty
2520 * Create a new Modal Dialog
2521 * @param {Object} config The config object
2524 Roo.bootstrap.Modal = function(config){
2525 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2530 * The raw btnclick event for the button
2531 * @param {Roo.EventObject} e
2536 * Fire when dialog resize
2537 * @param {Roo.bootstrap.Modal} this
2538 * @param {Roo.EventObject} e
2542 this.buttons = this.buttons || [];
2545 this.tmpl = Roo.factory(this.tmpl);
2550 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2552 title : 'test dialog',
2562 specificTitle: false,
2564 buttonPosition: 'right',
2583 onRender : function(ct, position)
2585 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2588 var cfg = Roo.apply({}, this.getAutoCreate());
2591 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2593 //if (!cfg.name.length) {
2597 cfg.cls += ' ' + this.cls;
2600 cfg.style = this.style;
2602 this.el = Roo.get(document.body).createChild(cfg, position);
2604 //var type = this.el.dom.type;
2607 if(this.tabIndex !== undefined){
2608 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2611 this.dialogEl = this.el.select('.modal-dialog',true).first();
2612 this.bodyEl = this.el.select('.modal-body',true).first();
2613 this.closeEl = this.el.select('.modal-header .close', true).first();
2614 this.headerEl = this.el.select('.modal-header',true).first();
2615 this.titleEl = this.el.select('.modal-title',true).first();
2616 this.footerEl = this.el.select('.modal-footer',true).first();
2618 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2619 this.maskEl.enableDisplayMode("block");
2621 //this.el.addClass("x-dlg-modal");
2623 if (this.buttons.length) {
2624 Roo.each(this.buttons, function(bb) {
2625 var b = Roo.apply({}, bb);
2626 b.xns = b.xns || Roo.bootstrap;
2627 b.xtype = b.xtype || 'Button';
2628 if (typeof(b.listeners) == 'undefined') {
2629 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2632 var btn = Roo.factory(b);
2634 btn.render(this.el.select('.modal-footer div').first());
2638 // render the children.
2641 if(typeof(this.items) != 'undefined'){
2642 var items = this.items;
2645 for(var i =0;i < items.length;i++) {
2646 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2650 this.items = nitems;
2652 // where are these used - they used to be body/close/footer
2656 //this.el.addClass([this.fieldClass, this.cls]);
2660 getAutoCreate : function(){
2665 html : this.html || ''
2670 cls : 'modal-title',
2674 if(this.specificTitle){
2680 if (this.allow_close) {
2692 if(this.size.length){
2693 size = 'modal-' + this.size;
2698 style : 'display: none',
2701 cls: "modal-dialog " + size,
2704 cls : "modal-content",
2707 cls : 'modal-header',
2712 cls : 'modal-footer',
2716 cls: 'btn-' + this.buttonPosition
2733 modal.cls += ' fade';
2739 getChildContainer : function() {
2744 getButtonContainer : function() {
2745 return this.el.select('.modal-footer div',true).first();
2748 initEvents : function()
2750 if (this.allow_close) {
2751 this.closeEl.on('click', this.hide, this);
2753 Roo.EventManager.onWindowResize(this.resize, this, true);
2760 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2761 if (this.fitwindow) {
2762 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2763 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2768 setSize : function(w,h)
2778 if (!this.rendered) {
2782 this.el.setStyle('display', 'block');
2784 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2787 this.el.addClass('in');
2790 this.el.addClass('in');
2794 // not sure how we can show data in here..
2796 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2799 Roo.get(document.body).addClass("x-body-masked");
2801 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2802 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2807 this.fireEvent('show', this);
2809 // set zindex here - otherwise it appears to be ignored...
2810 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2813 this.items.forEach( function(e) {
2814 e.layout ? e.layout() : false;
2822 if(this.fireEvent("beforehide", this) !== false){
2824 Roo.get(document.body).removeClass("x-body-masked");
2825 this.el.removeClass('in');
2826 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2828 if(this.animate){ // why
2830 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2832 this.el.setStyle('display', 'none');
2834 this.fireEvent('hide', this);
2838 addButton : function(str, cb)
2842 var b = Roo.apply({}, { html : str } );
2843 b.xns = b.xns || Roo.bootstrap;
2844 b.xtype = b.xtype || 'Button';
2845 if (typeof(b.listeners) == 'undefined') {
2846 b.listeners = { click : cb.createDelegate(this) };
2849 var btn = Roo.factory(b);
2851 btn.render(this.el.select('.modal-footer div').first());
2857 setDefaultButton : function(btn)
2859 //this.el.select('.modal-footer').()
2863 resizeTo: function(w,h)
2867 this.dialogEl.setWidth(w);
2868 if (this.diff === false) {
2869 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2872 this.bodyEl.setHeight(h-this.diff);
2874 this.fireEvent('resize', this);
2877 setContentSize : function(w, h)
2881 onButtonClick: function(btn,e)
2884 this.fireEvent('btnclick', btn.name, e);
2887 * Set the title of the Dialog
2888 * @param {String} str new Title
2890 setTitle: function(str) {
2891 this.titleEl.dom.innerHTML = str;
2894 * Set the body of the Dialog
2895 * @param {String} str new Title
2897 setBody: function(str) {
2898 this.bodyEl.dom.innerHTML = str;
2901 * Set the body of the Dialog using the template
2902 * @param {Obj} data - apply this data to the template and replace the body contents.
2904 applyBody: function(obj)
2907 Roo.log("Error - using apply Body without a template");
2910 this.tmpl.overwrite(this.bodyEl, obj);
2916 Roo.apply(Roo.bootstrap.Modal, {
2918 * Button config that displays a single OK button
2927 * Button config that displays Yes and No buttons
2943 * Button config that displays OK and Cancel buttons
2958 * Button config that displays Yes, No and Cancel buttons
2982 * messagebox - can be used as a replace
2986 * @class Roo.MessageBox
2987 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2991 Roo.Msg.alert('Status', 'Changes saved successfully.');
2993 // Prompt for user data:
2994 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2996 // process text value...
3000 // Show a dialog using config options:
3002 title:'Save Changes?',
3003 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3004 buttons: Roo.Msg.YESNOCANCEL,
3011 Roo.bootstrap.MessageBox = function(){
3012 var dlg, opt, mask, waitTimer;
3013 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3014 var buttons, activeTextEl, bwidth;
3018 var handleButton = function(button){
3020 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3024 var handleHide = function(){
3026 dlg.el.removeClass(opt.cls);
3029 // Roo.TaskMgr.stop(waitTimer);
3030 // waitTimer = null;
3035 var updateButtons = function(b){
3038 buttons["ok"].hide();
3039 buttons["cancel"].hide();
3040 buttons["yes"].hide();
3041 buttons["no"].hide();
3042 //dlg.footer.dom.style.display = 'none';
3045 dlg.footerEl.dom.style.display = '';
3046 for(var k in buttons){
3047 if(typeof buttons[k] != "function"){
3050 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3051 width += buttons[k].el.getWidth()+15;
3061 var handleEsc = function(d, k, e){
3062 if(opt && opt.closable !== false){
3072 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3073 * @return {Roo.BasicDialog} The BasicDialog element
3075 getDialog : function(){
3077 dlg = new Roo.bootstrap.Modal( {
3080 //constraintoviewport:false,
3082 //collapsible : false,
3087 //buttonAlign:"center",
3088 closeClick : function(){
3089 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3092 handleButton("cancel");
3097 dlg.on("hide", handleHide);
3099 //dlg.addKeyListener(27, handleEsc);
3101 this.buttons = buttons;
3102 var bt = this.buttonText;
3103 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3104 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3105 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3106 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3108 bodyEl = dlg.bodyEl.createChild({
3110 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3111 '<textarea class="roo-mb-textarea"></textarea>' +
3112 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3114 msgEl = bodyEl.dom.firstChild;
3115 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3116 textboxEl.enableDisplayMode();
3117 textboxEl.addKeyListener([10,13], function(){
3118 if(dlg.isVisible() && opt && opt.buttons){
3121 }else if(opt.buttons.yes){
3122 handleButton("yes");
3126 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3127 textareaEl.enableDisplayMode();
3128 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3129 progressEl.enableDisplayMode();
3131 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3132 var pf = progressEl.dom.firstChild;
3134 pp = Roo.get(pf.firstChild);
3135 pp.setHeight(pf.offsetHeight);
3143 * Updates the message box body text
3144 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3145 * the XHTML-compliant non-breaking space character '&#160;')
3146 * @return {Roo.MessageBox} This message box
3148 updateText : function(text)
3150 if(!dlg.isVisible() && !opt.width){
3151 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3152 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3154 msgEl.innerHTML = text || ' ';
3156 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3157 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3159 Math.min(opt.width || cw , this.maxWidth),
3160 Math.max(opt.minWidth || this.minWidth, bwidth)
3163 activeTextEl.setWidth(w);
3165 if(dlg.isVisible()){
3166 dlg.fixedcenter = false;
3168 // to big, make it scroll. = But as usual stupid IE does not support
3171 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3172 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3173 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3175 bodyEl.dom.style.height = '';
3176 bodyEl.dom.style.overflowY = '';
3179 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3181 bodyEl.dom.style.overflowX = '';
3184 dlg.setContentSize(w, bodyEl.getHeight());
3185 if(dlg.isVisible()){
3186 dlg.fixedcenter = true;
3192 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3193 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3194 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3195 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3196 * @return {Roo.MessageBox} This message box
3198 updateProgress : function(value, text){
3200 this.updateText(text);
3203 if (pp) { // weird bug on my firefox - for some reason this is not defined
3204 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3205 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3211 * Returns true if the message box is currently displayed
3212 * @return {Boolean} True if the message box is visible, else false
3214 isVisible : function(){
3215 return dlg && dlg.isVisible();
3219 * Hides the message box if it is displayed
3222 if(this.isVisible()){
3228 * Displays a new message box, or reinitializes an existing message box, based on the config options
3229 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3230 * The following config object properties are supported:
3232 Property Type Description
3233 ---------- --------------- ------------------------------------------------------------------------------------
3234 animEl String/Element An id or Element from which the message box should animate as it opens and
3235 closes (defaults to undefined)
3236 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3237 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3238 closable Boolean False to hide the top-right close button (defaults to true). Note that
3239 progress and wait dialogs will ignore this property and always hide the
3240 close button as they can only be closed programmatically.
3241 cls String A custom CSS class to apply to the message box element
3242 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3243 displayed (defaults to 75)
3244 fn Function A callback function to execute after closing the dialog. The arguments to the
3245 function will be btn (the name of the button that was clicked, if applicable,
3246 e.g. "ok"), and text (the value of the active text field, if applicable).
3247 Progress and wait dialogs will ignore this option since they do not respond to
3248 user actions and can only be closed programmatically, so any required function
3249 should be called by the same code after it closes the dialog.
3250 icon String A CSS class that provides a background image to be used as an icon for
3251 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3252 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3253 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3254 modal Boolean False to allow user interaction with the page while the message box is
3255 displayed (defaults to true)
3256 msg String A string that will replace the existing message box body text (defaults
3257 to the XHTML-compliant non-breaking space character ' ')
3258 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3259 progress Boolean True to display a progress bar (defaults to false)
3260 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3261 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3262 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3263 title String The title text
3264 value String The string value to set into the active textbox element if displayed
3265 wait Boolean True to display a progress bar (defaults to false)
3266 width Number The width of the dialog in pixels
3273 msg: 'Please enter your address:',
3275 buttons: Roo.MessageBox.OKCANCEL,
3278 animEl: 'addAddressBtn'
3281 * @param {Object} config Configuration options
3282 * @return {Roo.MessageBox} This message box
3284 show : function(options)
3287 // this causes nightmares if you show one dialog after another
3288 // especially on callbacks..
3290 if(this.isVisible()){
3293 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3294 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3295 Roo.log("New Dialog Message:" + options.msg )
3296 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3297 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3300 var d = this.getDialog();
3302 d.setTitle(opt.title || " ");
3303 d.closeEl.setDisplayed(opt.closable !== false);
3304 activeTextEl = textboxEl;
3305 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3310 textareaEl.setHeight(typeof opt.multiline == "number" ?
3311 opt.multiline : this.defaultTextHeight);
3312 activeTextEl = textareaEl;
3321 progressEl.setDisplayed(opt.progress === true);
3322 this.updateProgress(0);
3323 activeTextEl.dom.value = opt.value || "";
3325 dlg.setDefaultButton(activeTextEl);
3327 var bs = opt.buttons;
3331 }else if(bs && bs.yes){
3332 db = buttons["yes"];
3334 dlg.setDefaultButton(db);
3336 bwidth = updateButtons(opt.buttons);
3337 this.updateText(opt.msg);
3339 d.el.addClass(opt.cls);
3341 d.proxyDrag = opt.proxyDrag === true;
3342 d.modal = opt.modal !== false;
3343 d.mask = opt.modal !== false ? mask : false;
3345 // force it to the end of the z-index stack so it gets a cursor in FF
3346 document.body.appendChild(dlg.el.dom);
3347 d.animateTarget = null;
3348 d.show(options.animEl);
3354 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3355 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3356 * and closing the message box when the process is complete.
3357 * @param {String} title The title bar text
3358 * @param {String} msg The message box body text
3359 * @return {Roo.MessageBox} This message box
3361 progress : function(title, msg){
3368 minWidth: this.minProgressWidth,
3375 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3376 * If a callback function is passed it will be called after the user clicks the button, and the
3377 * id of the button that was clicked will be passed as the only parameter to the callback
3378 * (could also be the top-right close button).
3379 * @param {String} title The title bar text
3380 * @param {String} msg The message box body text
3381 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3382 * @param {Object} scope (optional) The scope of the callback function
3383 * @return {Roo.MessageBox} This message box
3385 alert : function(title, msg, fn, scope)
3400 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3401 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3402 * You are responsible for closing the message box when the process is complete.
3403 * @param {String} msg The message box body text
3404 * @param {String} title (optional) The title bar text
3405 * @return {Roo.MessageBox} This message box
3407 wait : function(msg, title){
3418 waitTimer = Roo.TaskMgr.start({
3420 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3428 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3429 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3430 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3431 * @param {String} title The title bar text
3432 * @param {String} msg The message box body text
3433 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3434 * @param {Object} scope (optional) The scope of the callback function
3435 * @return {Roo.MessageBox} This message box
3437 confirm : function(title, msg, fn, scope){
3441 buttons: this.YESNO,
3450 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3451 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3452 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3453 * (could also be the top-right close button) and the text that was entered will be passed as the two
3454 * parameters to the callback.
3455 * @param {String} title The title bar text
3456 * @param {String} msg The message box body text
3457 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3458 * @param {Object} scope (optional) The scope of the callback function
3459 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3460 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3461 * @return {Roo.MessageBox} This message box
3463 prompt : function(title, msg, fn, scope, multiline){
3467 buttons: this.OKCANCEL,
3472 multiline: multiline,
3479 * Button config that displays a single OK button
3484 * Button config that displays Yes and No buttons
3487 YESNO : {yes:true, no:true},
3489 * Button config that displays OK and Cancel buttons
3492 OKCANCEL : {ok:true, cancel:true},
3494 * Button config that displays Yes, No and Cancel buttons
3497 YESNOCANCEL : {yes:true, no:true, cancel:true},
3500 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3503 defaultTextHeight : 75,
3505 * The maximum width in pixels of the message box (defaults to 600)
3510 * The minimum width in pixels of the message box (defaults to 100)
3515 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3516 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3519 minProgressWidth : 250,
3521 * An object containing the default button text strings that can be overriden for localized language support.
3522 * Supported properties are: ok, cancel, yes and no.
3523 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3536 * Shorthand for {@link Roo.MessageBox}
3538 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3539 Roo.Msg = Roo.Msg || Roo.MessageBox;
3548 * @class Roo.bootstrap.Navbar
3549 * @extends Roo.bootstrap.Component
3550 * Bootstrap Navbar class
3553 * Create a new Navbar
3554 * @param {Object} config The config object
3558 Roo.bootstrap.Navbar = function(config){
3559 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3563 * @event beforetoggle
3564 * Fire before toggle the menu
3565 * @param {Roo.EventObject} e
3567 "beforetoggle" : true
3571 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3580 getAutoCreate : function(){
3583 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3587 initEvents :function ()
3589 //Roo.log(this.el.select('.navbar-toggle',true));
3590 this.el.select('.navbar-toggle',true).on('click', function() {
3591 if(this.fireEvent('beforetoggle', this) !== false){
3592 this.el.select('.navbar-collapse',true).toggleClass('in');
3602 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3604 var size = this.el.getSize();
3605 this.maskEl.setSize(size.width, size.height);
3606 this.maskEl.enableDisplayMode("block");
3615 getChildContainer : function()
3617 if (this.el.select('.collapse').getCount()) {
3618 return this.el.select('.collapse',true).first();
3651 * @class Roo.bootstrap.NavSimplebar
3652 * @extends Roo.bootstrap.Navbar
3653 * Bootstrap Sidebar class
3655 * @cfg {Boolean} inverse is inverted color
3657 * @cfg {String} type (nav | pills | tabs)
3658 * @cfg {Boolean} arrangement stacked | justified
3659 * @cfg {String} align (left | right) alignment
3661 * @cfg {Boolean} main (true|false) main nav bar? default false
3662 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3664 * @cfg {String} tag (header|footer|nav|div) default is nav
3670 * Create a new Sidebar
3671 * @param {Object} config The config object
3675 Roo.bootstrap.NavSimplebar = function(config){
3676 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3679 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3695 getAutoCreate : function(){
3699 tag : this.tag || 'div',
3712 this.type = this.type || 'nav';
3713 if (['tabs','pills'].indexOf(this.type)!==-1) {
3714 cfg.cn[0].cls += ' nav-' + this.type
3718 if (this.type!=='nav') {
3719 Roo.log('nav type must be nav/tabs/pills')
3721 cfg.cn[0].cls += ' navbar-nav'
3727 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3728 cfg.cn[0].cls += ' nav-' + this.arrangement;
3732 if (this.align === 'right') {
3733 cfg.cn[0].cls += ' navbar-right';
3737 cfg.cls += ' navbar-inverse';
3764 * @class Roo.bootstrap.NavHeaderbar
3765 * @extends Roo.bootstrap.NavSimplebar
3766 * Bootstrap Sidebar class
3768 * @cfg {String} brand what is brand
3769 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3770 * @cfg {String} brand_href href of the brand
3771 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3772 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3773 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3774 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3777 * Create a new Sidebar
3778 * @param {Object} config The config object
3782 Roo.bootstrap.NavHeaderbar = function(config){
3783 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3787 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3794 desktopCenter : false,
3797 getAutoCreate : function(){
3800 tag: this.nav || 'nav',
3807 if (this.desktopCenter) {
3808 cn.push({cls : 'container', cn : []});
3815 cls: 'navbar-header',
3820 cls: 'navbar-toggle',
3821 'data-toggle': 'collapse',
3826 html: 'Toggle navigation'
3848 cls: 'collapse navbar-collapse',
3852 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3854 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3855 cfg.cls += ' navbar-' + this.position;
3857 // tag can override this..
3859 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3862 if (this.brand !== '') {
3865 href: this.brand_href ? this.brand_href : '#',
3866 cls: 'navbar-brand',
3874 cfg.cls += ' main-nav';
3882 getHeaderChildContainer : function()
3884 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3885 return this.el.select('.navbar-header',true).first();
3888 return this.getChildContainer();
3892 initEvents : function()
3894 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3896 if (this.autohide) {
3901 Roo.get(document).on('scroll',function(e) {
3902 var ns = Roo.get(document).getScroll().top;
3903 var os = prevScroll;
3907 ft.removeClass('slideDown');
3908 ft.addClass('slideUp');
3911 ft.removeClass('slideUp');
3912 ft.addClass('slideDown');
3933 * @class Roo.bootstrap.NavSidebar
3934 * @extends Roo.bootstrap.Navbar
3935 * Bootstrap Sidebar class
3938 * Create a new Sidebar
3939 * @param {Object} config The config object
3943 Roo.bootstrap.NavSidebar = function(config){
3944 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3947 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3949 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3951 getAutoCreate : function(){
3956 cls: 'sidebar sidebar-nav'
3978 * @class Roo.bootstrap.NavGroup
3979 * @extends Roo.bootstrap.Component
3980 * Bootstrap NavGroup class
3981 * @cfg {String} align (left|right)
3982 * @cfg {Boolean} inverse
3983 * @cfg {String} type (nav|pills|tab) default nav
3984 * @cfg {String} navId - reference Id for navbar.
3988 * Create a new nav group
3989 * @param {Object} config The config object
3992 Roo.bootstrap.NavGroup = function(config){
3993 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3996 Roo.bootstrap.NavGroup.register(this);
4000 * Fires when the active item changes
4001 * @param {Roo.bootstrap.NavGroup} this
4002 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4003 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4010 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4021 getAutoCreate : function()
4023 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4030 if (['tabs','pills'].indexOf(this.type)!==-1) {
4031 cfg.cls += ' nav-' + this.type
4033 if (this.type!=='nav') {
4034 Roo.log('nav type must be nav/tabs/pills')
4036 cfg.cls += ' navbar-nav'
4039 if (this.parent() && this.parent().sidebar) {
4042 cls: 'dashboard-menu sidebar-menu'
4048 if (this.form === true) {
4054 if (this.align === 'right') {
4055 cfg.cls += ' navbar-right';
4057 cfg.cls += ' navbar-left';
4061 if (this.align === 'right') {
4062 cfg.cls += ' navbar-right';
4066 cfg.cls += ' navbar-inverse';
4074 * sets the active Navigation item
4075 * @param {Roo.bootstrap.NavItem} the new current navitem
4077 setActiveItem : function(item)
4080 Roo.each(this.navItems, function(v){
4085 v.setActive(false, true);
4092 item.setActive(true, true);
4093 this.fireEvent('changed', this, item, prev);
4098 * gets the active Navigation item
4099 * @return {Roo.bootstrap.NavItem} the current navitem
4101 getActive : function()
4105 Roo.each(this.navItems, function(v){
4116 indexOfNav : function()
4120 Roo.each(this.navItems, function(v,i){
4131 * adds a Navigation item
4132 * @param {Roo.bootstrap.NavItem} the navitem to add
4134 addItem : function(cfg)
4136 var cn = new Roo.bootstrap.NavItem(cfg);
4138 cn.parentId = this.id;
4139 cn.onRender(this.el, null);
4143 * register a Navigation item
4144 * @param {Roo.bootstrap.NavItem} the navitem to add
4146 register : function(item)
4148 this.navItems.push( item);
4149 item.navId = this.navId;
4154 * clear all the Navigation item
4157 clearAll : function()
4160 this.el.dom.innerHTML = '';
4163 getNavItem: function(tabId)
4166 Roo.each(this.navItems, function(e) {
4167 if (e.tabId == tabId) {
4177 setActiveNext : function()
4179 var i = this.indexOfNav(this.getActive());
4180 if (i > this.navItems.length) {
4183 this.setActiveItem(this.navItems[i+1]);
4185 setActivePrev : function()
4187 var i = this.indexOfNav(this.getActive());
4191 this.setActiveItem(this.navItems[i-1]);
4193 clearWasActive : function(except) {
4194 Roo.each(this.navItems, function(e) {
4195 if (e.tabId != except.tabId && e.was_active) {
4196 e.was_active = false;
4203 getWasActive : function ()
4206 Roo.each(this.navItems, function(e) {
4221 Roo.apply(Roo.bootstrap.NavGroup, {
4225 * register a Navigation Group
4226 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4228 register : function(navgrp)
4230 this.groups[navgrp.navId] = navgrp;
4234 * fetch a Navigation Group based on the navigation ID
4235 * @param {string} the navgroup to add
4236 * @returns {Roo.bootstrap.NavGroup} the navgroup
4238 get: function(navId) {
4239 if (typeof(this.groups[navId]) == 'undefined') {
4241 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4243 return this.groups[navId] ;
4258 * @class Roo.bootstrap.NavItem
4259 * @extends Roo.bootstrap.Component
4260 * Bootstrap Navbar.NavItem class
4261 * @cfg {String} href link to
4262 * @cfg {String} html content of button
4263 * @cfg {String} badge text inside badge
4264 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4265 * @cfg {String} glyphicon name of glyphicon
4266 * @cfg {String} icon name of font awesome icon
4267 * @cfg {Boolean} active Is item active
4268 * @cfg {Boolean} disabled Is item disabled
4270 * @cfg {Boolean} preventDefault (true | false) default false
4271 * @cfg {String} tabId the tab that this item activates.
4272 * @cfg {String} tagtype (a|span) render as a href or span?
4273 * @cfg {Boolean} animateRef (true|false) link to element default false
4276 * Create a new Navbar Item
4277 * @param {Object} config The config object
4279 Roo.bootstrap.NavItem = function(config){
4280 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4285 * The raw click event for the entire grid.
4286 * @param {Roo.EventObject} e
4291 * Fires when the active item active state changes
4292 * @param {Roo.bootstrap.NavItem} this
4293 * @param {boolean} state the new state
4299 * Fires when scroll to element
4300 * @param {Roo.bootstrap.NavItem} this
4301 * @param {Object} options
4302 * @param {Roo.EventObject} e
4310 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4318 preventDefault : false,
4325 getAutoCreate : function(){
4334 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4336 if (this.disabled) {
4337 cfg.cls += ' disabled';
4340 if (this.href || this.html || this.glyphicon || this.icon) {
4344 href : this.href || "#",
4345 html: this.html || ''
4350 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4353 if(this.glyphicon) {
4354 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4359 cfg.cn[0].html += " <span class='caret'></span>";
4363 if (this.badge !== '') {
4365 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4373 initEvents: function()
4375 if (typeof (this.menu) != 'undefined') {
4376 this.menu.parentType = this.xtype;
4377 this.menu.triggerEl = this.el;
4378 this.menu = this.addxtype(Roo.apply({}, this.menu));
4381 this.el.select('a',true).on('click', this.onClick, this);
4383 if(this.tagtype == 'span'){
4384 this.el.select('span',true).on('click', this.onClick, this);
4387 // at this point parent should be available..
4388 this.parent().register(this);
4391 onClick : function(e)
4393 if (e.getTarget('.dropdown-menu-item')) {
4394 // did you click on a menu itemm.... - then don't trigger onclick..
4399 this.preventDefault ||
4402 Roo.log("NavItem - prevent Default?");
4406 if (this.disabled) {
4410 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4411 if (tg && tg.transition) {
4412 Roo.log("waiting for the transitionend");
4418 //Roo.log("fire event clicked");
4419 if(this.fireEvent('click', this, e) === false){
4423 if(this.tagtype == 'span'){
4427 //Roo.log(this.href);
4428 var ael = this.el.select('a',true).first();
4431 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4432 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4433 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4434 return; // ignore... - it's a 'hash' to another page.
4436 Roo.log("NavItem - prevent Default?");
4438 this.scrollToElement(e);
4442 var p = this.parent();
4444 if (['tabs','pills'].indexOf(p.type)!==-1) {
4445 if (typeof(p.setActiveItem) !== 'undefined') {
4446 p.setActiveItem(this);
4450 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4451 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4452 // remove the collapsed menu expand...
4453 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4457 isActive: function () {
4460 setActive : function(state, fire, is_was_active)
4462 if (this.active && !state && this.navId) {
4463 this.was_active = true;
4464 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4466 nv.clearWasActive(this);
4470 this.active = state;
4473 this.el.removeClass('active');
4474 } else if (!this.el.hasClass('active')) {
4475 this.el.addClass('active');
4478 this.fireEvent('changed', this, state);
4481 // show a panel if it's registered and related..
4483 if (!this.navId || !this.tabId || !state || is_was_active) {
4487 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4491 var pan = tg.getPanelByName(this.tabId);
4495 // if we can not flip to new panel - go back to old nav highlight..
4496 if (false == tg.showPanel(pan)) {
4497 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4499 var onav = nv.getWasActive();
4501 onav.setActive(true, false, true);
4510 // this should not be here...
4511 setDisabled : function(state)
4513 this.disabled = state;
4515 this.el.removeClass('disabled');
4516 } else if (!this.el.hasClass('disabled')) {
4517 this.el.addClass('disabled');
4523 * Fetch the element to display the tooltip on.
4524 * @return {Roo.Element} defaults to this.el
4526 tooltipEl : function()
4528 return this.el.select('' + this.tagtype + '', true).first();
4531 scrollToElement : function(e)
4533 var c = document.body;
4536 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4538 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4539 c = document.documentElement;
4542 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4548 var o = target.calcOffsetsTo(c);
4555 this.fireEvent('scrollto', this, options, e);
4557 Roo.get(c).scrollTo('top', options.value, true);
4570 * <span> icon </span>
4571 * <span> text </span>
4572 * <span>badge </span>
4576 * @class Roo.bootstrap.NavSidebarItem
4577 * @extends Roo.bootstrap.NavItem
4578 * Bootstrap Navbar.NavSidebarItem class
4579 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4580 * {Boolean} open is the menu open
4581 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4582 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4583 * {String} buttonSize (sm|md|lg)the extra classes for the button
4584 * {Boolean} showArrow show arrow next to the text (default true)
4586 * Create a new Navbar Button
4587 * @param {Object} config The config object
4589 Roo.bootstrap.NavSidebarItem = function(config){
4590 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4595 * The raw click event for the entire grid.
4596 * @param {Roo.EventObject} e
4601 * Fires when the active item active state changes
4602 * @param {Roo.bootstrap.NavSidebarItem} this
4603 * @param {boolean} state the new state
4611 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4613 badgeWeight : 'default',
4619 buttonWeight : 'default',
4625 getAutoCreate : function(){
4630 href : this.href || '#',
4636 if(this.buttonView){
4639 href : this.href || '#',
4640 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4653 cfg.cls += ' active';
4656 if (this.disabled) {
4657 cfg.cls += ' disabled';
4660 cfg.cls += ' open x-open';
4663 if (this.glyphicon || this.icon) {
4664 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4665 a.cn.push({ tag : 'i', cls : c }) ;
4668 if(!this.buttonView){
4671 html : this.html || ''
4678 if (this.badge !== '') {
4679 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4685 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4688 a.cls += ' dropdown-toggle treeview' ;
4694 initEvents : function()
4696 if (typeof (this.menu) != 'undefined') {
4697 this.menu.parentType = this.xtype;
4698 this.menu.triggerEl = this.el;
4699 this.menu = this.addxtype(Roo.apply({}, this.menu));
4702 this.el.on('click', this.onClick, this);
4704 if(this.badge !== ''){
4705 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4710 onClick : function(e)
4717 if(this.preventDefault){
4721 this.fireEvent('click', this);
4724 disable : function()
4726 this.setDisabled(true);
4731 this.setDisabled(false);
4734 setDisabled : function(state)
4736 if(this.disabled == state){
4740 this.disabled = state;
4743 this.el.addClass('disabled');
4747 this.el.removeClass('disabled');
4752 setActive : function(state)
4754 if(this.active == state){
4758 this.active = state;
4761 this.el.addClass('active');
4765 this.el.removeClass('active');
4770 isActive: function ()
4775 setBadge : function(str)
4781 this.badgeEl.dom.innerHTML = str;
4798 * @class Roo.bootstrap.Row
4799 * @extends Roo.bootstrap.Component
4800 * Bootstrap Row class (contains columns...)
4804 * @param {Object} config The config object
4807 Roo.bootstrap.Row = function(config){
4808 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4811 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4813 getAutoCreate : function(){
4832 * @class Roo.bootstrap.Element
4833 * @extends Roo.bootstrap.Component
4834 * Bootstrap Element class
4835 * @cfg {String} html contents of the element
4836 * @cfg {String} tag tag of the element
4837 * @cfg {String} cls class of the element
4838 * @cfg {Boolean} preventDefault (true|false) default false
4839 * @cfg {Boolean} clickable (true|false) default false
4842 * Create a new Element
4843 * @param {Object} config The config object
4846 Roo.bootstrap.Element = function(config){
4847 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4853 * When a element is chick
4854 * @param {Roo.bootstrap.Element} this
4855 * @param {Roo.EventObject} e
4861 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4866 preventDefault: false,
4869 getAutoCreate : function(){
4880 initEvents: function()
4882 Roo.bootstrap.Element.superclass.initEvents.call(this);
4885 this.el.on('click', this.onClick, this);
4890 onClick : function(e)
4892 if(this.preventDefault){
4896 this.fireEvent('click', this, e);
4899 getValue : function()
4901 return this.el.dom.innerHTML;
4904 setValue : function(value)
4906 this.el.dom.innerHTML = value;
4921 * @class Roo.bootstrap.Pagination
4922 * @extends Roo.bootstrap.Component
4923 * Bootstrap Pagination class
4924 * @cfg {String} size xs | sm | md | lg
4925 * @cfg {Boolean} inverse false | true
4928 * Create a new Pagination
4929 * @param {Object} config The config object
4932 Roo.bootstrap.Pagination = function(config){
4933 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4936 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4942 getAutoCreate : function(){
4948 cfg.cls += ' inverse';
4954 cfg.cls += " " + this.cls;
4972 * @class Roo.bootstrap.PaginationItem
4973 * @extends Roo.bootstrap.Component
4974 * Bootstrap PaginationItem class
4975 * @cfg {String} html text
4976 * @cfg {String} href the link
4977 * @cfg {Boolean} preventDefault (true | false) default true
4978 * @cfg {Boolean} active (true | false) default false
4979 * @cfg {Boolean} disabled default false
4983 * Create a new PaginationItem
4984 * @param {Object} config The config object
4988 Roo.bootstrap.PaginationItem = function(config){
4989 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4994 * The raw click event for the entire grid.
4995 * @param {Roo.EventObject} e
5001 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5005 preventDefault: true,
5010 getAutoCreate : function(){
5016 href : this.href ? this.href : '#',
5017 html : this.html ? this.html : ''
5027 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5031 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5037 initEvents: function() {
5039 this.el.on('click', this.onClick, this);
5042 onClick : function(e)
5044 Roo.log('PaginationItem on click ');
5045 if(this.preventDefault){
5053 this.fireEvent('click', this, e);
5069 * @class Roo.bootstrap.Slider
5070 * @extends Roo.bootstrap.Component
5071 * Bootstrap Slider class
5074 * Create a new Slider
5075 * @param {Object} config The config object
5078 Roo.bootstrap.Slider = function(config){
5079 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5082 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5084 getAutoCreate : function(){
5088 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5092 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5104 * Ext JS Library 1.1.1
5105 * Copyright(c) 2006-2007, Ext JS, LLC.
5107 * Originally Released Under LGPL - original licence link has changed is not relivant.
5110 * <script type="text/javascript">
5115 * @class Roo.grid.ColumnModel
5116 * @extends Roo.util.Observable
5117 * This is the default implementation of a ColumnModel used by the Grid. It defines
5118 * the columns in the grid.
5121 var colModel = new Roo.grid.ColumnModel([
5122 {header: "Ticker", width: 60, sortable: true, locked: true},
5123 {header: "Company Name", width: 150, sortable: true},
5124 {header: "Market Cap.", width: 100, sortable: true},
5125 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5126 {header: "Employees", width: 100, sortable: true, resizable: false}
5131 * The config options listed for this class are options which may appear in each
5132 * individual column definition.
5133 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5135 * @param {Object} config An Array of column config objects. See this class's
5136 * config objects for details.
5138 Roo.grid.ColumnModel = function(config){
5140 * The config passed into the constructor
5142 this.config = config;
5145 // if no id, create one
5146 // if the column does not have a dataIndex mapping,
5147 // map it to the order it is in the config
5148 for(var i = 0, len = config.length; i < len; i++){
5150 if(typeof c.dataIndex == "undefined"){
5153 if(typeof c.renderer == "string"){
5154 c.renderer = Roo.util.Format[c.renderer];
5156 if(typeof c.id == "undefined"){
5159 if(c.editor && c.editor.xtype){
5160 c.editor = Roo.factory(c.editor, Roo.grid);
5162 if(c.editor && c.editor.isFormField){
5163 c.editor = new Roo.grid.GridEditor(c.editor);
5165 this.lookup[c.id] = c;
5169 * The width of columns which have no width specified (defaults to 100)
5172 this.defaultWidth = 100;
5175 * Default sortable of columns which have no sortable specified (defaults to false)
5178 this.defaultSortable = false;
5182 * @event widthchange
5183 * Fires when the width of a column changes.
5184 * @param {ColumnModel} this
5185 * @param {Number} columnIndex The column index
5186 * @param {Number} newWidth The new width
5188 "widthchange": true,
5190 * @event headerchange
5191 * Fires when the text of a header changes.
5192 * @param {ColumnModel} this
5193 * @param {Number} columnIndex The column index
5194 * @param {Number} newText The new header text
5196 "headerchange": true,
5198 * @event hiddenchange
5199 * Fires when a column is hidden or "unhidden".
5200 * @param {ColumnModel} this
5201 * @param {Number} columnIndex The column index
5202 * @param {Boolean} hidden true if hidden, false otherwise
5204 "hiddenchange": true,
5206 * @event columnmoved
5207 * Fires when a column is moved.
5208 * @param {ColumnModel} this
5209 * @param {Number} oldIndex
5210 * @param {Number} newIndex
5212 "columnmoved" : true,
5214 * @event columlockchange
5215 * Fires when a column's locked state is changed
5216 * @param {ColumnModel} this
5217 * @param {Number} colIndex
5218 * @param {Boolean} locked true if locked
5220 "columnlockchange" : true
5222 Roo.grid.ColumnModel.superclass.constructor.call(this);
5224 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5226 * @cfg {String} header The header text to display in the Grid view.
5229 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5230 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5231 * specified, the column's index is used as an index into the Record's data Array.
5234 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5235 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5238 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5239 * Defaults to the value of the {@link #defaultSortable} property.
5240 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5243 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5246 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5249 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5252 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5255 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5256 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5257 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5258 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5261 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5264 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5267 * @cfg {String} cursor (Optional)
5270 * @cfg {String} tooltip (Optional)
5273 * @cfg {Number} xs (Optional)
5276 * @cfg {Number} sm (Optional)
5279 * @cfg {Number} md (Optional)
5282 * @cfg {Number} lg (Optional)
5285 * Returns the id of the column at the specified index.
5286 * @param {Number} index The column index
5287 * @return {String} the id
5289 getColumnId : function(index){
5290 return this.config[index].id;
5294 * Returns the column for a specified id.
5295 * @param {String} id The column id
5296 * @return {Object} the column
5298 getColumnById : function(id){
5299 return this.lookup[id];
5304 * Returns the column for a specified dataIndex.
5305 * @param {String} dataIndex The column dataIndex
5306 * @return {Object|Boolean} the column or false if not found
5308 getColumnByDataIndex: function(dataIndex){
5309 var index = this.findColumnIndex(dataIndex);
5310 return index > -1 ? this.config[index] : false;
5314 * Returns the index for a specified column id.
5315 * @param {String} id The column id
5316 * @return {Number} the index, or -1 if not found
5318 getIndexById : function(id){
5319 for(var i = 0, len = this.config.length; i < len; i++){
5320 if(this.config[i].id == id){
5328 * Returns the index for a specified column dataIndex.
5329 * @param {String} dataIndex The column dataIndex
5330 * @return {Number} the index, or -1 if not found
5333 findColumnIndex : function(dataIndex){
5334 for(var i = 0, len = this.config.length; i < len; i++){
5335 if(this.config[i].dataIndex == dataIndex){
5343 moveColumn : function(oldIndex, newIndex){
5344 var c = this.config[oldIndex];
5345 this.config.splice(oldIndex, 1);
5346 this.config.splice(newIndex, 0, c);
5347 this.dataMap = null;
5348 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5351 isLocked : function(colIndex){
5352 return this.config[colIndex].locked === true;
5355 setLocked : function(colIndex, value, suppressEvent){
5356 if(this.isLocked(colIndex) == value){
5359 this.config[colIndex].locked = value;
5361 this.fireEvent("columnlockchange", this, colIndex, value);
5365 getTotalLockedWidth : function(){
5367 for(var i = 0; i < this.config.length; i++){
5368 if(this.isLocked(i) && !this.isHidden(i)){
5369 this.totalWidth += this.getColumnWidth(i);
5375 getLockedCount : function(){
5376 for(var i = 0, len = this.config.length; i < len; i++){
5377 if(!this.isLocked(i)){
5382 return this.config.length;
5386 * Returns the number of columns.
5389 getColumnCount : function(visibleOnly){
5390 if(visibleOnly === true){
5392 for(var i = 0, len = this.config.length; i < len; i++){
5393 if(!this.isHidden(i)){
5399 return this.config.length;
5403 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5404 * @param {Function} fn
5405 * @param {Object} scope (optional)
5406 * @return {Array} result
5408 getColumnsBy : function(fn, scope){
5410 for(var i = 0, len = this.config.length; i < len; i++){
5411 var c = this.config[i];
5412 if(fn.call(scope||this, c, i) === true){
5420 * Returns true if the specified column is sortable.
5421 * @param {Number} col The column index
5424 isSortable : function(col){
5425 if(typeof this.config[col].sortable == "undefined"){
5426 return this.defaultSortable;
5428 return this.config[col].sortable;
5432 * Returns the rendering (formatting) function defined for the column.
5433 * @param {Number} col The column index.
5434 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5436 getRenderer : function(col){
5437 if(!this.config[col].renderer){
5438 return Roo.grid.ColumnModel.defaultRenderer;
5440 return this.config[col].renderer;
5444 * Sets the rendering (formatting) function for a column.
5445 * @param {Number} col The column index
5446 * @param {Function} fn The function to use to process the cell's raw data
5447 * to return HTML markup for the grid view. The render function is called with
5448 * the following parameters:<ul>
5449 * <li>Data value.</li>
5450 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5451 * <li>css A CSS style string to apply to the table cell.</li>
5452 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5453 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5454 * <li>Row index</li>
5455 * <li>Column index</li>
5456 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5458 setRenderer : function(col, fn){
5459 this.config[col].renderer = fn;
5463 * Returns the width for the specified column.
5464 * @param {Number} col The column index
5467 getColumnWidth : function(col){
5468 return this.config[col].width * 1 || this.defaultWidth;
5472 * Sets the width for a column.
5473 * @param {Number} col The column index
5474 * @param {Number} width The new width
5476 setColumnWidth : function(col, width, suppressEvent){
5477 this.config[col].width = width;
5478 this.totalWidth = null;
5480 this.fireEvent("widthchange", this, col, width);
5485 * Returns the total width of all columns.
5486 * @param {Boolean} includeHidden True to include hidden column widths
5489 getTotalWidth : function(includeHidden){
5490 if(!this.totalWidth){
5491 this.totalWidth = 0;
5492 for(var i = 0, len = this.config.length; i < len; i++){
5493 if(includeHidden || !this.isHidden(i)){
5494 this.totalWidth += this.getColumnWidth(i);
5498 return this.totalWidth;
5502 * Returns the header for the specified column.
5503 * @param {Number} col The column index
5506 getColumnHeader : function(col){
5507 return this.config[col].header;
5511 * Sets the header for a column.
5512 * @param {Number} col The column index
5513 * @param {String} header The new header
5515 setColumnHeader : function(col, header){
5516 this.config[col].header = header;
5517 this.fireEvent("headerchange", this, col, header);
5521 * Returns the tooltip for the specified column.
5522 * @param {Number} col The column index
5525 getColumnTooltip : function(col){
5526 return this.config[col].tooltip;
5529 * Sets the tooltip for a column.
5530 * @param {Number} col The column index
5531 * @param {String} tooltip The new tooltip
5533 setColumnTooltip : function(col, tooltip){
5534 this.config[col].tooltip = tooltip;
5538 * Returns the dataIndex for the specified column.
5539 * @param {Number} col The column index
5542 getDataIndex : function(col){
5543 return this.config[col].dataIndex;
5547 * Sets the dataIndex for a column.
5548 * @param {Number} col The column index
5549 * @param {Number} dataIndex The new dataIndex
5551 setDataIndex : function(col, dataIndex){
5552 this.config[col].dataIndex = dataIndex;
5558 * Returns true if the cell is editable.
5559 * @param {Number} colIndex The column index
5560 * @param {Number} rowIndex The row index - this is nto actually used..?
5563 isCellEditable : function(colIndex, rowIndex){
5564 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5568 * Returns the editor defined for the cell/column.
5569 * return false or null to disable editing.
5570 * @param {Number} colIndex The column index
5571 * @param {Number} rowIndex The row index
5574 getCellEditor : function(colIndex, rowIndex){
5575 return this.config[colIndex].editor;
5579 * Sets if a column is editable.
5580 * @param {Number} col The column index
5581 * @param {Boolean} editable True if the column is editable
5583 setEditable : function(col, editable){
5584 this.config[col].editable = editable;
5589 * Returns true if the column is hidden.
5590 * @param {Number} colIndex The column index
5593 isHidden : function(colIndex){
5594 return this.config[colIndex].hidden;
5599 * Returns true if the column width cannot be changed
5601 isFixed : function(colIndex){
5602 return this.config[colIndex].fixed;
5606 * Returns true if the column can be resized
5609 isResizable : function(colIndex){
5610 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5613 * Sets if a column is hidden.
5614 * @param {Number} colIndex The column index
5615 * @param {Boolean} hidden True if the column is hidden
5617 setHidden : function(colIndex, hidden){
5618 this.config[colIndex].hidden = hidden;
5619 this.totalWidth = null;
5620 this.fireEvent("hiddenchange", this, colIndex, hidden);
5624 * Sets the editor for a column.
5625 * @param {Number} col The column index
5626 * @param {Object} editor The editor object
5628 setEditor : function(col, editor){
5629 this.config[col].editor = editor;
5633 Roo.grid.ColumnModel.defaultRenderer = function(value)
5635 if(typeof value == "object") {
5638 if(typeof value == "string" && value.length < 1){
5642 return String.format("{0}", value);
5645 // Alias for backwards compatibility
5646 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5649 * Ext JS Library 1.1.1
5650 * Copyright(c) 2006-2007, Ext JS, LLC.
5652 * Originally Released Under LGPL - original licence link has changed is not relivant.
5655 * <script type="text/javascript">
5659 * @class Roo.LoadMask
5660 * A simple utility class for generically masking elements while loading data. If the element being masked has
5661 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5662 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5663 * element's UpdateManager load indicator and will be destroyed after the initial load.
5665 * Create a new LoadMask
5666 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5667 * @param {Object} config The config object
5669 Roo.LoadMask = function(el, config){
5670 this.el = Roo.get(el);
5671 Roo.apply(this, config);
5673 this.store.on('beforeload', this.onBeforeLoad, this);
5674 this.store.on('load', this.onLoad, this);
5675 this.store.on('loadexception', this.onLoadException, this);
5676 this.removeMask = false;
5678 var um = this.el.getUpdateManager();
5679 um.showLoadIndicator = false; // disable the default indicator
5680 um.on('beforeupdate', this.onBeforeLoad, this);
5681 um.on('update', this.onLoad, this);
5682 um.on('failure', this.onLoad, this);
5683 this.removeMask = true;
5687 Roo.LoadMask.prototype = {
5689 * @cfg {Boolean} removeMask
5690 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5691 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5695 * The text to display in a centered loading message box (defaults to 'Loading...')
5699 * @cfg {String} msgCls
5700 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5702 msgCls : 'x-mask-loading',
5705 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5711 * Disables the mask to prevent it from being displayed
5713 disable : function(){
5714 this.disabled = true;
5718 * Enables the mask so that it can be displayed
5720 enable : function(){
5721 this.disabled = false;
5724 onLoadException : function()
5728 if (typeof(arguments[3]) != 'undefined') {
5729 Roo.MessageBox.alert("Error loading",arguments[3]);
5733 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5734 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5741 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5746 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5750 onBeforeLoad : function(){
5752 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5757 destroy : function(){
5759 this.store.un('beforeload', this.onBeforeLoad, this);
5760 this.store.un('load', this.onLoad, this);
5761 this.store.un('loadexception', this.onLoadException, this);
5763 var um = this.el.getUpdateManager();
5764 um.un('beforeupdate', this.onBeforeLoad, this);
5765 um.un('update', this.onLoad, this);
5766 um.un('failure', this.onLoad, this);
5777 * @class Roo.bootstrap.Table
5778 * @extends Roo.bootstrap.Component
5779 * Bootstrap Table class
5780 * @cfg {String} cls table class
5781 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5782 * @cfg {String} bgcolor Specifies the background color for a table
5783 * @cfg {Number} border Specifies whether the table cells should have borders or not
5784 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5785 * @cfg {Number} cellspacing Specifies the space between cells
5786 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5787 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5788 * @cfg {String} sortable Specifies that the table should be sortable
5789 * @cfg {String} summary Specifies a summary of the content of a table
5790 * @cfg {Number} width Specifies the width of a table
5791 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5793 * @cfg {boolean} striped Should the rows be alternative striped
5794 * @cfg {boolean} bordered Add borders to the table
5795 * @cfg {boolean} hover Add hover highlighting
5796 * @cfg {boolean} condensed Format condensed
5797 * @cfg {boolean} responsive Format condensed
5798 * @cfg {Boolean} loadMask (true|false) default false
5799 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5800 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5801 * @cfg {Boolean} rowSelection (true|false) default false
5802 * @cfg {Boolean} cellSelection (true|false) default false
5803 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5804 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5805 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5809 * Create a new Table
5810 * @param {Object} config The config object
5813 Roo.bootstrap.Table = function(config){
5814 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5819 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5820 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5821 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5822 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5824 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5826 this.sm.grid = this;
5827 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5828 this.sm = this.selModel;
5829 this.sm.xmodule = this.xmodule || false;
5832 if (this.cm && typeof(this.cm.config) == 'undefined') {
5833 this.colModel = new Roo.grid.ColumnModel(this.cm);
5834 this.cm = this.colModel;
5835 this.cm.xmodule = this.xmodule || false;
5838 this.store= Roo.factory(this.store, Roo.data);
5839 this.ds = this.store;
5840 this.ds.xmodule = this.xmodule || false;
5843 if (this.footer && this.store) {
5844 this.footer.dataSource = this.ds;
5845 this.footer = Roo.factory(this.footer);
5852 * Fires when a cell is clicked
5853 * @param {Roo.bootstrap.Table} this
5854 * @param {Roo.Element} el
5855 * @param {Number} rowIndex
5856 * @param {Number} columnIndex
5857 * @param {Roo.EventObject} e
5861 * @event celldblclick
5862 * Fires when a cell is double clicked
5863 * @param {Roo.bootstrap.Table} this
5864 * @param {Roo.Element} el
5865 * @param {Number} rowIndex
5866 * @param {Number} columnIndex
5867 * @param {Roo.EventObject} e
5869 "celldblclick" : true,
5872 * Fires when a row is clicked
5873 * @param {Roo.bootstrap.Table} this
5874 * @param {Roo.Element} el
5875 * @param {Number} rowIndex
5876 * @param {Roo.EventObject} e
5880 * @event rowdblclick
5881 * Fires when a row is double clicked
5882 * @param {Roo.bootstrap.Table} this
5883 * @param {Roo.Element} el
5884 * @param {Number} rowIndex
5885 * @param {Roo.EventObject} e
5887 "rowdblclick" : true,
5890 * Fires when a mouseover occur
5891 * @param {Roo.bootstrap.Table} this
5892 * @param {Roo.Element} el
5893 * @param {Number} rowIndex
5894 * @param {Number} columnIndex
5895 * @param {Roo.EventObject} e
5900 * Fires when a mouseout occur
5901 * @param {Roo.bootstrap.Table} this
5902 * @param {Roo.Element} el
5903 * @param {Number} rowIndex
5904 * @param {Number} columnIndex
5905 * @param {Roo.EventObject} e
5910 * Fires when a row is rendered, so you can change add a style to it.
5911 * @param {Roo.bootstrap.Table} this
5912 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5916 * @event rowsrendered
5917 * Fires when all the rows have been rendered
5918 * @param {Roo.bootstrap.Table} this
5920 'rowsrendered' : true,
5922 * @event contextmenu
5923 * The raw contextmenu event for the entire grid.
5924 * @param {Roo.EventObject} e
5926 "contextmenu" : true,
5928 * @event rowcontextmenu
5929 * Fires when a row is right clicked
5930 * @param {Roo.bootstrap.Table} this
5931 * @param {Number} rowIndex
5932 * @param {Roo.EventObject} e
5934 "rowcontextmenu" : true,
5936 * @event cellcontextmenu
5937 * Fires when a cell is right clicked
5938 * @param {Roo.bootstrap.Table} this
5939 * @param {Number} rowIndex
5940 * @param {Number} cellIndex
5941 * @param {Roo.EventObject} e
5943 "cellcontextmenu" : true,
5945 * @event headercontextmenu
5946 * Fires when a header is right clicked
5947 * @param {Roo.bootstrap.Table} this
5948 * @param {Number} columnIndex
5949 * @param {Roo.EventObject} e
5951 "headercontextmenu" : true
5955 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5981 rowSelection : false,
5982 cellSelection : false,
5985 // Roo.Element - the tbody
5987 // Roo.Element - thead element
5990 container: false, // used by gridpanel...
5994 getAutoCreate : function()
5996 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6003 if (this.scrollBody) {
6004 cfg.cls += ' table-body-fixed';
6007 cfg.cls += ' table-striped';
6011 cfg.cls += ' table-hover';
6013 if (this.bordered) {
6014 cfg.cls += ' table-bordered';
6016 if (this.condensed) {
6017 cfg.cls += ' table-condensed';
6019 if (this.responsive) {
6020 cfg.cls += ' table-responsive';
6024 cfg.cls+= ' ' +this.cls;
6027 // this lot should be simplifed...
6030 cfg.align=this.align;
6033 cfg.bgcolor=this.bgcolor;
6036 cfg.border=this.border;
6038 if (this.cellpadding) {
6039 cfg.cellpadding=this.cellpadding;
6041 if (this.cellspacing) {
6042 cfg.cellspacing=this.cellspacing;
6045 cfg.frame=this.frame;
6048 cfg.rules=this.rules;
6050 if (this.sortable) {
6051 cfg.sortable=this.sortable;
6054 cfg.summary=this.summary;
6057 cfg.width=this.width;
6060 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6063 if(this.store || this.cm){
6064 if(this.headerShow){
6065 cfg.cn.push(this.renderHeader());
6068 cfg.cn.push(this.renderBody());
6070 if(this.footerShow){
6071 cfg.cn.push(this.renderFooter());
6073 // where does this come from?
6074 //cfg.cls+= ' TableGrid';
6077 return { cn : [ cfg ] };
6080 initEvents : function()
6082 if(!this.store || !this.cm){
6085 if (this.selModel) {
6086 this.selModel.initEvents();
6090 //Roo.log('initEvents with ds!!!!');
6092 this.mainBody = this.el.select('tbody', true).first();
6093 this.mainHead = this.el.select('thead', true).first();
6100 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6101 e.on('click', _this.sort, _this);
6104 this.mainBody.on("click", this.onClick, this);
6105 this.mainBody.on("dblclick", this.onDblClick, this);
6107 // why is this done????? = it breaks dialogs??
6108 //this.parent().el.setStyle('position', 'relative');
6112 this.footer.parentId = this.id;
6113 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6116 this.el.select('tfoot tr td').first().addClass('hide');
6120 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6122 this.store.on('load', this.onLoad, this);
6123 this.store.on('beforeload', this.onBeforeLoad, this);
6124 this.store.on('update', this.onUpdate, this);
6125 this.store.on('add', this.onAdd, this);
6126 this.store.on("clear", this.clear, this);
6128 this.el.on("contextmenu", this.onContextMenu, this);
6130 this.mainBody.on('scroll', this.onBodyScroll, this);
6135 onContextMenu : function(e, t)
6137 this.processEvent("contextmenu", e);
6140 processEvent : function(name, e)
6142 if (name != 'touchstart' ) {
6143 this.fireEvent(name, e);
6146 var t = e.getTarget();
6148 var cell = Roo.get(t);
6154 if(cell.findParent('tfoot', false, true)){
6158 if(cell.findParent('thead', false, true)){
6160 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6161 cell = Roo.get(t).findParent('th', false, true);
6163 Roo.log("failed to find th in thead?");
6164 Roo.log(e.getTarget());
6169 var cellIndex = cell.dom.cellIndex;
6171 var ename = name == 'touchstart' ? 'click' : name;
6172 this.fireEvent("header" + ename, this, cellIndex, e);
6177 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6178 cell = Roo.get(t).findParent('td', false, true);
6180 Roo.log("failed to find th in tbody?");
6181 Roo.log(e.getTarget());
6186 var row = cell.findParent('tr', false, true);
6187 var cellIndex = cell.dom.cellIndex;
6188 var rowIndex = row.dom.rowIndex - 1;
6192 this.fireEvent("row" + name, this, rowIndex, e);
6196 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6202 onMouseover : function(e, el)
6204 var cell = Roo.get(el);
6210 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6211 cell = cell.findParent('td', false, true);
6214 var row = cell.findParent('tr', false, true);
6215 var cellIndex = cell.dom.cellIndex;
6216 var rowIndex = row.dom.rowIndex - 1; // start from 0
6218 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6222 onMouseout : function(e, el)
6224 var cell = Roo.get(el);
6230 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6231 cell = cell.findParent('td', false, true);
6234 var row = cell.findParent('tr', false, true);
6235 var cellIndex = cell.dom.cellIndex;
6236 var rowIndex = row.dom.rowIndex - 1; // start from 0
6238 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6242 onClick : function(e, el)
6244 var cell = Roo.get(el);
6246 if(!cell || (!this.cellSelection && !this.rowSelection)){
6250 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6251 cell = cell.findParent('td', false, true);
6254 if(!cell || typeof(cell) == 'undefined'){
6258 var row = cell.findParent('tr', false, true);
6260 if(!row || typeof(row) == 'undefined'){
6264 var cellIndex = cell.dom.cellIndex;
6265 var rowIndex = this.getRowIndex(row);
6267 // why??? - should these not be based on SelectionModel?
6268 if(this.cellSelection){
6269 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6272 if(this.rowSelection){
6273 this.fireEvent('rowclick', this, row, rowIndex, e);
6279 onDblClick : function(e,el)
6281 var cell = Roo.get(el);
6283 if(!cell || (!this.cellSelection && !this.rowSelection)){
6287 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6288 cell = cell.findParent('td', false, true);
6291 if(!cell || typeof(cell) == 'undefined'){
6295 var row = cell.findParent('tr', false, true);
6297 if(!row || typeof(row) == 'undefined'){
6301 var cellIndex = cell.dom.cellIndex;
6302 var rowIndex = this.getRowIndex(row);
6304 if(this.cellSelection){
6305 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6308 if(this.rowSelection){
6309 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6313 sort : function(e,el)
6315 var col = Roo.get(el);
6317 if(!col.hasClass('sortable')){
6321 var sort = col.attr('sort');
6324 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6328 this.store.sortInfo = {field : sort, direction : dir};
6331 Roo.log("calling footer first");
6332 this.footer.onClick('first');
6335 this.store.load({ params : { start : 0 } });
6339 renderHeader : function()
6347 this.totalWidth = 0;
6349 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6351 var config = cm.config[i];
6356 html: cm.getColumnHeader(i)
6361 if(typeof(config.sortable) != 'undefined' && config.sortable){
6363 c.html = '<i class="glyphicon"></i>' + c.html;
6366 if(typeof(config.lgHeader) != 'undefined'){
6367 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6370 if(typeof(config.mdHeader) != 'undefined'){
6371 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6374 if(typeof(config.smHeader) != 'undefined'){
6375 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6378 if(typeof(config.xsHeader) != 'undefined'){
6379 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6386 if(typeof(config.tooltip) != 'undefined'){
6387 c.tooltip = config.tooltip;
6390 if(typeof(config.colspan) != 'undefined'){
6391 c.colspan = config.colspan;
6394 if(typeof(config.hidden) != 'undefined' && config.hidden){
6395 c.style += ' display:none;';
6398 if(typeof(config.dataIndex) != 'undefined'){
6399 c.sort = config.dataIndex;
6404 if(typeof(config.align) != 'undefined' && config.align.length){
6405 c.style += ' text-align:' + config.align + ';';
6408 if(typeof(config.width) != 'undefined'){
6409 c.style += ' width:' + config.width + 'px;';
6410 this.totalWidth += config.width;
6412 this.totalWidth += 100; // assume minimum of 100 per column?
6415 if(typeof(config.cls) != 'undefined'){
6416 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6419 ['xs','sm','md','lg'].map(function(size){
6421 if(typeof(config[size]) == 'undefined'){
6425 if (!config[size]) { // 0 = hidden
6426 c.cls += ' hidden-' + size;
6430 c.cls += ' col-' + size + '-' + config[size];
6440 renderBody : function()
6450 colspan : this.cm.getColumnCount()
6460 renderFooter : function()
6470 colspan : this.cm.getColumnCount()
6484 // Roo.log('ds onload');
6489 var ds = this.store;
6491 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6492 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6493 if (_this.store.sortInfo) {
6495 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6496 e.select('i', true).addClass(['glyphicon-arrow-up']);
6499 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6500 e.select('i', true).addClass(['glyphicon-arrow-down']);
6505 var tbody = this.mainBody;
6507 if(ds.getCount() > 0){
6508 ds.data.each(function(d,rowIndex){
6509 var row = this.renderRow(cm, ds, rowIndex);
6511 tbody.createChild(row);
6515 if(row.cellObjects.length){
6516 Roo.each(row.cellObjects, function(r){
6517 _this.renderCellObject(r);
6524 Roo.each(this.el.select('tbody td', true).elements, function(e){
6525 e.on('mouseover', _this.onMouseover, _this);
6528 Roo.each(this.el.select('tbody td', true).elements, function(e){
6529 e.on('mouseout', _this.onMouseout, _this);
6531 this.fireEvent('rowsrendered', this);
6532 //if(this.loadMask){
6533 // this.maskEl.hide();
6540 onUpdate : function(ds,record)
6542 this.refreshRow(record);
6546 onRemove : function(ds, record, index, isUpdate){
6547 if(isUpdate !== true){
6548 this.fireEvent("beforerowremoved", this, index, record);
6550 var bt = this.mainBody.dom;
6552 var rows = this.el.select('tbody > tr', true).elements;
6554 if(typeof(rows[index]) != 'undefined'){
6555 bt.removeChild(rows[index].dom);
6558 // if(bt.rows[index]){
6559 // bt.removeChild(bt.rows[index]);
6562 if(isUpdate !== true){
6563 //this.stripeRows(index);
6564 //this.syncRowHeights(index, index);
6566 this.fireEvent("rowremoved", this, index, record);
6570 onAdd : function(ds, records, rowIndex)
6572 //Roo.log('on Add called');
6573 // - note this does not handle multiple adding very well..
6574 var bt = this.mainBody.dom;
6575 for (var i =0 ; i < records.length;i++) {
6576 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6577 //Roo.log(records[i]);
6578 //Roo.log(this.store.getAt(rowIndex+i));
6579 this.insertRow(this.store, rowIndex + i, false);
6586 refreshRow : function(record){
6587 var ds = this.store, index;
6588 if(typeof record == 'number'){
6590 record = ds.getAt(index);
6592 index = ds.indexOf(record);
6594 this.insertRow(ds, index, true);
6596 this.onRemove(ds, record, index+1, true);
6598 //this.syncRowHeights(index, index);
6600 this.fireEvent("rowupdated", this, index, record);
6603 insertRow : function(dm, rowIndex, isUpdate){
6606 this.fireEvent("beforerowsinserted", this, rowIndex);
6608 //var s = this.getScrollState();
6609 var row = this.renderRow(this.cm, this.store, rowIndex);
6610 // insert before rowIndex..
6611 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6615 if(row.cellObjects.length){
6616 Roo.each(row.cellObjects, function(r){
6617 _this.renderCellObject(r);
6622 this.fireEvent("rowsinserted", this, rowIndex);
6623 //this.syncRowHeights(firstRow, lastRow);
6624 //this.stripeRows(firstRow);
6631 getRowDom : function(rowIndex)
6633 var rows = this.el.select('tbody > tr', true).elements;
6635 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6638 // returns the object tree for a tr..
6641 renderRow : function(cm, ds, rowIndex)
6644 var d = ds.getAt(rowIndex);
6651 var cellObjects = [];
6653 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6654 var config = cm.config[i];
6656 var renderer = cm.getRenderer(i);
6660 if(typeof(renderer) !== 'undefined'){
6661 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6663 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6664 // and are rendered into the cells after the row is rendered - using the id for the element.
6666 if(typeof(value) === 'object'){
6676 rowIndex : rowIndex,
6681 this.fireEvent('rowclass', this, rowcfg);
6685 cls : rowcfg.rowClass,
6687 html: (typeof(value) === 'object') ? '' : value
6694 if(typeof(config.colspan) != 'undefined'){
6695 td.colspan = config.colspan;
6698 if(typeof(config.hidden) != 'undefined' && config.hidden){
6699 td.style += ' display:none;';
6702 if(typeof(config.align) != 'undefined' && config.align.length){
6703 td.style += ' text-align:' + config.align + ';';
6706 if(typeof(config.width) != 'undefined'){
6707 td.style += ' width:' + config.width + 'px;';
6710 if(typeof(config.cursor) != 'undefined'){
6711 td.style += ' cursor:' + config.cursor + ';';
6714 if(typeof(config.cls) != 'undefined'){
6715 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6718 ['xs','sm','md','lg'].map(function(size){
6720 if(typeof(config[size]) == 'undefined'){
6724 if (!config[size]) { // 0 = hidden
6725 td.cls += ' hidden-' + size;
6729 td.cls += ' col-' + size + '-' + config[size];
6737 row.cellObjects = cellObjects;
6745 onBeforeLoad : function()
6747 //Roo.log('ds onBeforeLoad');
6751 //if(this.loadMask){
6752 // this.maskEl.show();
6760 this.el.select('tbody', true).first().dom.innerHTML = '';
6763 * Show or hide a row.
6764 * @param {Number} rowIndex to show or hide
6765 * @param {Boolean} state hide
6767 setRowVisibility : function(rowIndex, state)
6769 var bt = this.mainBody.dom;
6771 var rows = this.el.select('tbody > tr', true).elements;
6773 if(typeof(rows[rowIndex]) == 'undefined'){
6776 rows[rowIndex].dom.style.display = state ? '' : 'none';
6780 getSelectionModel : function(){
6782 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6784 return this.selModel;
6787 * Render the Roo.bootstrap object from renderder
6789 renderCellObject : function(r)
6793 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6795 var t = r.cfg.render(r.container);
6798 Roo.each(r.cfg.cn, function(c){
6800 container: t.getChildContainer(),
6803 _this.renderCellObject(child);
6808 getRowIndex : function(row)
6812 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6823 * Returns the grid's underlying element = used by panel.Grid
6824 * @return {Element} The element
6826 getGridEl : function(){
6830 * Forces a resize - used by panel.Grid
6831 * @return {Element} The element
6833 autoSize : function()
6835 //var ctr = Roo.get(this.container.dom.parentElement);
6836 var ctr = Roo.get(this.el.dom);
6838 var thd = this.getGridEl().select('thead',true).first();
6839 var tbd = this.getGridEl().select('tbody', true).first();
6840 var tfd = this.getGridEl().select('tfoot', true).first();
6842 var cw = ctr.getWidth();
6846 tbd.setSize(ctr.getWidth(),
6847 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6849 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6852 cw = Math.max(cw, this.totalWidth);
6853 this.getGridEl().select('tr',true).setWidth(cw);
6854 // resize 'expandable coloumn?
6856 return; // we doe not have a view in this design..
6859 onBodyScroll: function()
6861 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6862 this.mainHead.setStyle({
6863 'position' : 'relative',
6864 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6869 var scrollHeight = this.mainBody.dom.scrollHeight;
6871 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6873 var height = this.mainBody.getHeight();
6875 if(scrollHeight - height == scrollTop) {
6877 var total = this.ds.getTotalCount();
6879 if(this.footer.cursor + this.footer.pageSize < total){
6881 this.footer.ds.load({
6883 start : this.footer.cursor + this.footer.pageSize,
6884 limit : this.footer.pageSize
6905 * @class Roo.bootstrap.TableCell
6906 * @extends Roo.bootstrap.Component
6907 * Bootstrap TableCell class
6908 * @cfg {String} html cell contain text
6909 * @cfg {String} cls cell class
6910 * @cfg {String} tag cell tag (td|th) default td
6911 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6912 * @cfg {String} align Aligns the content in a cell
6913 * @cfg {String} axis Categorizes cells
6914 * @cfg {String} bgcolor Specifies the background color of a cell
6915 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6916 * @cfg {Number} colspan Specifies the number of columns a cell should span
6917 * @cfg {String} headers Specifies one or more header cells a cell is related to
6918 * @cfg {Number} height Sets the height of a cell
6919 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6920 * @cfg {Number} rowspan Sets the number of rows a cell should span
6921 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6922 * @cfg {String} valign Vertical aligns the content in a cell
6923 * @cfg {Number} width Specifies the width of a cell
6926 * Create a new TableCell
6927 * @param {Object} config The config object
6930 Roo.bootstrap.TableCell = function(config){
6931 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6934 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6954 getAutoCreate : function(){
6955 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6975 cfg.align=this.align
6981 cfg.bgcolor=this.bgcolor
6984 cfg.charoff=this.charoff
6987 cfg.colspan=this.colspan
6990 cfg.headers=this.headers
6993 cfg.height=this.height
6996 cfg.nowrap=this.nowrap
6999 cfg.rowspan=this.rowspan
7002 cfg.scope=this.scope
7005 cfg.valign=this.valign
7008 cfg.width=this.width
7027 * @class Roo.bootstrap.TableRow
7028 * @extends Roo.bootstrap.Component
7029 * Bootstrap TableRow class
7030 * @cfg {String} cls row class
7031 * @cfg {String} align Aligns the content in a table row
7032 * @cfg {String} bgcolor Specifies a background color for a table row
7033 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7034 * @cfg {String} valign Vertical aligns the content in a table row
7037 * Create a new TableRow
7038 * @param {Object} config The config object
7041 Roo.bootstrap.TableRow = function(config){
7042 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7045 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7053 getAutoCreate : function(){
7054 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7064 cfg.align = this.align;
7067 cfg.bgcolor = this.bgcolor;
7070 cfg.charoff = this.charoff;
7073 cfg.valign = this.valign;
7091 * @class Roo.bootstrap.TableBody
7092 * @extends Roo.bootstrap.Component
7093 * Bootstrap TableBody class
7094 * @cfg {String} cls element class
7095 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7096 * @cfg {String} align Aligns the content inside the element
7097 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7098 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7101 * Create a new TableBody
7102 * @param {Object} config The config object
7105 Roo.bootstrap.TableBody = function(config){
7106 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7109 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7117 getAutoCreate : function(){
7118 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7132 cfg.align = this.align;
7135 cfg.charoff = this.charoff;
7138 cfg.valign = this.valign;
7145 // initEvents : function()
7152 // this.store = Roo.factory(this.store, Roo.data);
7153 // this.store.on('load', this.onLoad, this);
7155 // this.store.load();
7159 // onLoad: function ()
7161 // this.fireEvent('load', this);
7171 * Ext JS Library 1.1.1
7172 * Copyright(c) 2006-2007, Ext JS, LLC.
7174 * Originally Released Under LGPL - original licence link has changed is not relivant.
7177 * <script type="text/javascript">
7180 // as we use this in bootstrap.
7181 Roo.namespace('Roo.form');
7183 * @class Roo.form.Action
7184 * Internal Class used to handle form actions
7186 * @param {Roo.form.BasicForm} el The form element or its id
7187 * @param {Object} config Configuration options
7192 // define the action interface
7193 Roo.form.Action = function(form, options){
7195 this.options = options || {};
7198 * Client Validation Failed
7201 Roo.form.Action.CLIENT_INVALID = 'client';
7203 * Server Validation Failed
7206 Roo.form.Action.SERVER_INVALID = 'server';
7208 * Connect to Server Failed
7211 Roo.form.Action.CONNECT_FAILURE = 'connect';
7213 * Reading Data from Server Failed
7216 Roo.form.Action.LOAD_FAILURE = 'load';
7218 Roo.form.Action.prototype = {
7220 failureType : undefined,
7221 response : undefined,
7225 run : function(options){
7230 success : function(response){
7235 handleResponse : function(response){
7239 // default connection failure
7240 failure : function(response){
7242 this.response = response;
7243 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7244 this.form.afterAction(this, false);
7247 processResponse : function(response){
7248 this.response = response;
7249 if(!response.responseText){
7252 this.result = this.handleResponse(response);
7256 // utility functions used internally
7257 getUrl : function(appendParams){
7258 var url = this.options.url || this.form.url || this.form.el.dom.action;
7260 var p = this.getParams();
7262 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7268 getMethod : function(){
7269 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7272 getParams : function(){
7273 var bp = this.form.baseParams;
7274 var p = this.options.params;
7276 if(typeof p == "object"){
7277 p = Roo.urlEncode(Roo.applyIf(p, bp));
7278 }else if(typeof p == 'string' && bp){
7279 p += '&' + Roo.urlEncode(bp);
7282 p = Roo.urlEncode(bp);
7287 createCallback : function(){
7289 success: this.success,
7290 failure: this.failure,
7292 timeout: (this.form.timeout*1000),
7293 upload: this.form.fileUpload ? this.success : undefined
7298 Roo.form.Action.Submit = function(form, options){
7299 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7302 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7305 haveProgress : false,
7306 uploadComplete : false,
7308 // uploadProgress indicator.
7309 uploadProgress : function()
7311 if (!this.form.progressUrl) {
7315 if (!this.haveProgress) {
7316 Roo.MessageBox.progress("Uploading", "Uploading");
7318 if (this.uploadComplete) {
7319 Roo.MessageBox.hide();
7323 this.haveProgress = true;
7325 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7327 var c = new Roo.data.Connection();
7329 url : this.form.progressUrl,
7334 success : function(req){
7335 //console.log(data);
7339 rdata = Roo.decode(req.responseText)
7341 Roo.log("Invalid data from server..");
7345 if (!rdata || !rdata.success) {
7347 Roo.MessageBox.alert(Roo.encode(rdata));
7350 var data = rdata.data;
7352 if (this.uploadComplete) {
7353 Roo.MessageBox.hide();
7358 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7359 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7362 this.uploadProgress.defer(2000,this);
7365 failure: function(data) {
7366 Roo.log('progress url failed ');
7377 // run get Values on the form, so it syncs any secondary forms.
7378 this.form.getValues();
7380 var o = this.options;
7381 var method = this.getMethod();
7382 var isPost = method == 'POST';
7383 if(o.clientValidation === false || this.form.isValid()){
7385 if (this.form.progressUrl) {
7386 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7387 (new Date() * 1) + '' + Math.random());
7392 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7393 form:this.form.el.dom,
7394 url:this.getUrl(!isPost),
7396 params:isPost ? this.getParams() : null,
7397 isUpload: this.form.fileUpload
7400 this.uploadProgress();
7402 }else if (o.clientValidation !== false){ // client validation failed
7403 this.failureType = Roo.form.Action.CLIENT_INVALID;
7404 this.form.afterAction(this, false);
7408 success : function(response)
7410 this.uploadComplete= true;
7411 if (this.haveProgress) {
7412 Roo.MessageBox.hide();
7416 var result = this.processResponse(response);
7417 if(result === true || result.success){
7418 this.form.afterAction(this, true);
7422 this.form.markInvalid(result.errors);
7423 this.failureType = Roo.form.Action.SERVER_INVALID;
7425 this.form.afterAction(this, false);
7427 failure : function(response)
7429 this.uploadComplete= true;
7430 if (this.haveProgress) {
7431 Roo.MessageBox.hide();
7434 this.response = response;
7435 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7436 this.form.afterAction(this, false);
7439 handleResponse : function(response){
7440 if(this.form.errorReader){
7441 var rs = this.form.errorReader.read(response);
7444 for(var i = 0, len = rs.records.length; i < len; i++) {
7445 var r = rs.records[i];
7449 if(errors.length < 1){
7453 success : rs.success,
7459 ret = Roo.decode(response.responseText);
7463 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7473 Roo.form.Action.Load = function(form, options){
7474 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7475 this.reader = this.form.reader;
7478 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7483 Roo.Ajax.request(Roo.apply(
7484 this.createCallback(), {
7485 method:this.getMethod(),
7486 url:this.getUrl(false),
7487 params:this.getParams()
7491 success : function(response){
7493 var result = this.processResponse(response);
7494 if(result === true || !result.success || !result.data){
7495 this.failureType = Roo.form.Action.LOAD_FAILURE;
7496 this.form.afterAction(this, false);
7499 this.form.clearInvalid();
7500 this.form.setValues(result.data);
7501 this.form.afterAction(this, true);
7504 handleResponse : function(response){
7505 if(this.form.reader){
7506 var rs = this.form.reader.read(response);
7507 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7509 success : rs.success,
7513 return Roo.decode(response.responseText);
7517 Roo.form.Action.ACTION_TYPES = {
7518 'load' : Roo.form.Action.Load,
7519 'submit' : Roo.form.Action.Submit
7528 * @class Roo.bootstrap.Form
7529 * @extends Roo.bootstrap.Component
7530 * Bootstrap Form class
7531 * @cfg {String} method GET | POST (default POST)
7532 * @cfg {String} labelAlign top | left (default top)
7533 * @cfg {String} align left | right - for navbars
7534 * @cfg {Boolean} loadMask load mask when submit (default true)
7539 * @param {Object} config The config object
7543 Roo.bootstrap.Form = function(config){
7544 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7546 Roo.bootstrap.Form.popover.apply();
7550 * @event clientvalidation
7551 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7552 * @param {Form} this
7553 * @param {Boolean} valid true if the form has passed client-side validation
7555 clientvalidation: true,
7557 * @event beforeaction
7558 * Fires before any action is performed. Return false to cancel the action.
7559 * @param {Form} this
7560 * @param {Action} action The action to be performed
7564 * @event actionfailed
7565 * Fires when an action fails.
7566 * @param {Form} this
7567 * @param {Action} action The action that failed
7569 actionfailed : true,
7571 * @event actioncomplete
7572 * Fires when an action is completed.
7573 * @param {Form} this
7574 * @param {Action} action The action that completed
7576 actioncomplete : true
7581 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7584 * @cfg {String} method
7585 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7590 * The URL to use for form actions if one isn't supplied in the action options.
7593 * @cfg {Boolean} fileUpload
7594 * Set to true if this form is a file upload.
7598 * @cfg {Object} baseParams
7599 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7603 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7607 * @cfg {Sting} align (left|right) for navbar forms
7612 activeAction : null,
7615 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7616 * element by passing it or its id or mask the form itself by passing in true.
7619 waitMsgTarget : false,
7624 * @cfg {Boolean} errorMask (true|false) default false
7629 * @cfg {Number} maskOffset Default 100
7634 * @cfg {Boolean} maskBody
7638 getAutoCreate : function(){
7642 method : this.method || 'POST',
7643 id : this.id || Roo.id(),
7646 if (this.parent().xtype.match(/^Nav/)) {
7647 cfg.cls = 'navbar-form navbar-' + this.align;
7651 if (this.labelAlign == 'left' ) {
7652 cfg.cls += ' form-horizontal';
7658 initEvents : function()
7660 this.el.on('submit', this.onSubmit, this);
7661 // this was added as random key presses on the form where triggering form submit.
7662 this.el.on('keypress', function(e) {
7663 if (e.getCharCode() != 13) {
7666 // we might need to allow it for textareas.. and some other items.
7667 // check e.getTarget().
7669 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7673 Roo.log("keypress blocked");
7681 onSubmit : function(e){
7686 * Returns true if client-side validation on the form is successful.
7689 isValid : function(){
7690 var items = this.getItems();
7694 items.each(function(f){
7700 if(!target && f.el.isVisible(true)){
7706 if(this.errorMask && !valid){
7707 Roo.bootstrap.Form.popover.mask(this, target);
7714 * Returns true if any fields in this form have changed since their original load.
7717 isDirty : function(){
7719 var items = this.getItems();
7720 items.each(function(f){
7730 * Performs a predefined action (submit or load) or custom actions you define on this form.
7731 * @param {String} actionName The name of the action type
7732 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7733 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7734 * accept other config options):
7736 Property Type Description
7737 ---------------- --------------- ----------------------------------------------------------------------------------
7738 url String The url for the action (defaults to the form's url)
7739 method String The form method to use (defaults to the form's method, or POST if not defined)
7740 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7741 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7742 validate the form on the client (defaults to false)
7744 * @return {BasicForm} this
7746 doAction : function(action, options){
7747 if(typeof action == 'string'){
7748 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7750 if(this.fireEvent('beforeaction', this, action) !== false){
7751 this.beforeAction(action);
7752 action.run.defer(100, action);
7758 beforeAction : function(action){
7759 var o = action.options;
7764 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7766 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7769 // not really supported yet.. ??
7771 //if(this.waitMsgTarget === true){
7772 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7773 //}else if(this.waitMsgTarget){
7774 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7775 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7777 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7783 afterAction : function(action, success){
7784 this.activeAction = null;
7785 var o = action.options;
7790 Roo.get(document.body).unmask();
7796 //if(this.waitMsgTarget === true){
7797 // this.el.unmask();
7798 //}else if(this.waitMsgTarget){
7799 // this.waitMsgTarget.unmask();
7801 // Roo.MessageBox.updateProgress(1);
7802 // Roo.MessageBox.hide();
7809 Roo.callback(o.success, o.scope, [this, action]);
7810 this.fireEvent('actioncomplete', this, action);
7814 // failure condition..
7815 // we have a scenario where updates need confirming.
7816 // eg. if a locking scenario exists..
7817 // we look for { errors : { needs_confirm : true }} in the response.
7819 (typeof(action.result) != 'undefined') &&
7820 (typeof(action.result.errors) != 'undefined') &&
7821 (typeof(action.result.errors.needs_confirm) != 'undefined')
7824 Roo.log("not supported yet");
7827 Roo.MessageBox.confirm(
7828 "Change requires confirmation",
7829 action.result.errorMsg,
7834 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7844 Roo.callback(o.failure, o.scope, [this, action]);
7845 // show an error message if no failed handler is set..
7846 if (!this.hasListener('actionfailed')) {
7847 Roo.log("need to add dialog support");
7849 Roo.MessageBox.alert("Error",
7850 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7851 action.result.errorMsg :
7852 "Saving Failed, please check your entries or try again"
7857 this.fireEvent('actionfailed', this, action);
7862 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7863 * @param {String} id The value to search for
7866 findField : function(id){
7867 var items = this.getItems();
7868 var field = items.get(id);
7870 items.each(function(f){
7871 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7878 return field || null;
7881 * Mark fields in this form invalid in bulk.
7882 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7883 * @return {BasicForm} this
7885 markInvalid : function(errors){
7886 if(errors instanceof Array){
7887 for(var i = 0, len = errors.length; i < len; i++){
7888 var fieldError = errors[i];
7889 var f = this.findField(fieldError.id);
7891 f.markInvalid(fieldError.msg);
7897 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7898 field.markInvalid(errors[id]);
7902 //Roo.each(this.childForms || [], function (f) {
7903 // f.markInvalid(errors);
7910 * Set values for fields in this form in bulk.
7911 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7912 * @return {BasicForm} this
7914 setValues : function(values){
7915 if(values instanceof Array){ // array of objects
7916 for(var i = 0, len = values.length; i < len; i++){
7918 var f = this.findField(v.id);
7920 f.setValue(v.value);
7921 if(this.trackResetOnLoad){
7922 f.originalValue = f.getValue();
7926 }else{ // object hash
7929 if(typeof values[id] != 'function' && (field = this.findField(id))){
7931 if (field.setFromData &&
7933 field.displayField &&
7934 // combos' with local stores can
7935 // be queried via setValue()
7936 // to set their value..
7937 (field.store && !field.store.isLocal)
7941 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7942 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7943 field.setFromData(sd);
7945 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7947 field.setFromData(values);
7950 field.setValue(values[id]);
7954 if(this.trackResetOnLoad){
7955 field.originalValue = field.getValue();
7961 //Roo.each(this.childForms || [], function (f) {
7962 // f.setValues(values);
7969 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7970 * they are returned as an array.
7971 * @param {Boolean} asString
7974 getValues : function(asString){
7975 //if (this.childForms) {
7976 // copy values from the child forms
7977 // Roo.each(this.childForms, function (f) {
7978 // this.setValues(f.getValues());
7984 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7985 if(asString === true){
7988 return Roo.urlDecode(fs);
7992 * Returns the fields in this form as an object with key/value pairs.
7993 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7996 getFieldValues : function(with_hidden)
7998 var items = this.getItems();
8000 items.each(function(f){
8006 var v = f.getValue();
8008 if (f.inputType =='radio') {
8009 if (typeof(ret[f.getName()]) == 'undefined') {
8010 ret[f.getName()] = ''; // empty..
8013 if (!f.el.dom.checked) {
8021 if(f.xtype == 'MoneyField'){
8022 ret[f.currencyName] = f.getCurrency();
8025 // not sure if this supported any more..
8026 if ((typeof(v) == 'object') && f.getRawValue) {
8027 v = f.getRawValue() ; // dates..
8029 // combo boxes where name != hiddenName...
8030 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8031 ret[f.name] = f.getRawValue();
8033 ret[f.getName()] = v;
8040 * Clears all invalid messages in this form.
8041 * @return {BasicForm} this
8043 clearInvalid : function(){
8044 var items = this.getItems();
8046 items.each(function(f){
8057 * @return {BasicForm} this
8060 var items = this.getItems();
8061 items.each(function(f){
8065 Roo.each(this.childForms || [], function (f) {
8073 getItems : function()
8075 var r=new Roo.util.MixedCollection(false, function(o){
8076 return o.id || (o.id = Roo.id());
8078 var iter = function(el) {
8085 Roo.each(el.items,function(e) {
8099 Roo.apply(Roo.bootstrap.Form, {
8126 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8127 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8128 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8129 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8132 this.maskEl.top.enableDisplayMode("block");
8133 this.maskEl.left.enableDisplayMode("block");
8134 this.maskEl.bottom.enableDisplayMode("block");
8135 this.maskEl.right.enableDisplayMode("block");
8137 this.toolTip = new Roo.bootstrap.Tooltip({
8138 cls : 'roo-form-error-popover',
8140 'left' : ['r-l', [-2,0], 'right'],
8141 'right' : ['l-r', [2,0], 'left'],
8142 'bottom' : ['tl-bl', [0,2], 'top'],
8143 'top' : [ 'bl-tl', [0,-2], 'bottom']
8147 this.toolTip.render(Roo.get(document.body));
8149 this.toolTip.el.enableDisplayMode("block");
8151 Roo.get(document.body).on('click', function(){
8155 Roo.get(document.body).on('touchstart', function(){
8159 this.isApplied = true
8162 mask : function(form, target)
8166 this.target = target;
8168 if(!this.form.errorMask || !target.el){
8172 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8174 Roo.log(scrollable);
8176 var ot = this.target.el.calcOffsetsTo(scrollable);
8178 var scrollTo = ot[1] - this.form.maskOffset;
8180 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8182 scrollable.scrollTo('top', scrollTo);
8184 var box = this.target.el.getBox();
8186 var zIndex = Roo.bootstrap.Modal.zIndex++;
8189 this.maskEl.top.setStyle('position', 'absolute');
8190 this.maskEl.top.setStyle('z-index', zIndex);
8191 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8192 this.maskEl.top.setLeft(0);
8193 this.maskEl.top.setTop(0);
8194 this.maskEl.top.show();
8196 this.maskEl.left.setStyle('position', 'absolute');
8197 this.maskEl.left.setStyle('z-index', zIndex);
8198 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8199 this.maskEl.left.setLeft(0);
8200 this.maskEl.left.setTop(box.y - this.padding);
8201 this.maskEl.left.show();
8203 this.maskEl.bottom.setStyle('position', 'absolute');
8204 this.maskEl.bottom.setStyle('z-index', zIndex);
8205 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8206 this.maskEl.bottom.setLeft(0);
8207 this.maskEl.bottom.setTop(box.bottom + this.padding);
8208 this.maskEl.bottom.show();
8210 this.maskEl.right.setStyle('position', 'absolute');
8211 this.maskEl.right.setStyle('z-index', zIndex);
8212 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8213 this.maskEl.right.setLeft(box.right + this.padding);
8214 this.maskEl.right.setTop(box.y - this.padding);
8215 this.maskEl.right.show();
8217 this.toolTip.bindEl = this.target.el;
8219 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8221 var tip = this.target.blankText;
8223 if(this.target.getValue() !== '' ) {
8225 if (this.target.invalidText.length) {
8226 tip = this.target.invalidText;
8227 } else if (this.target.regexText.length){
8228 tip = this.target.regexText;
8232 this.toolTip.show(tip);
8234 this.intervalID = window.setInterval(function() {
8235 Roo.bootstrap.Form.popover.unmask();
8238 window.onwheel = function(){ return false;};
8240 (function(){ this.isMasked = true; }).defer(500, this);
8246 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8250 this.maskEl.top.setStyle('position', 'absolute');
8251 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8252 this.maskEl.top.hide();
8254 this.maskEl.left.setStyle('position', 'absolute');
8255 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8256 this.maskEl.left.hide();
8258 this.maskEl.bottom.setStyle('position', 'absolute');
8259 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8260 this.maskEl.bottom.hide();
8262 this.maskEl.right.setStyle('position', 'absolute');
8263 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8264 this.maskEl.right.hide();
8266 this.toolTip.hide();
8268 this.toolTip.el.hide();
8270 window.onwheel = function(){ return true;};
8272 if(this.intervalID){
8273 window.clearInterval(this.intervalID);
8274 this.intervalID = false;
8277 this.isMasked = false;
8287 * Ext JS Library 1.1.1
8288 * Copyright(c) 2006-2007, Ext JS, LLC.
8290 * Originally Released Under LGPL - original licence link has changed is not relivant.
8293 * <script type="text/javascript">
8296 * @class Roo.form.VTypes
8297 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8300 Roo.form.VTypes = function(){
8301 // closure these in so they are only created once.
8302 var alpha = /^[a-zA-Z_]+$/;
8303 var alphanum = /^[a-zA-Z0-9_]+$/;
8304 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8305 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8307 // All these messages and functions are configurable
8310 * The function used to validate email addresses
8311 * @param {String} value The email address
8313 'email' : function(v){
8314 return email.test(v);
8317 * The error text to display when the email validation function returns false
8320 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8322 * The keystroke filter mask to be applied on email input
8325 'emailMask' : /[a-z0-9_\.\-@]/i,
8328 * The function used to validate URLs
8329 * @param {String} value The URL
8331 'url' : function(v){
8335 * The error text to display when the url validation function returns false
8338 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8341 * The function used to validate alpha values
8342 * @param {String} value The value
8344 'alpha' : function(v){
8345 return alpha.test(v);
8348 * The error text to display when the alpha validation function returns false
8351 'alphaText' : 'This field should only contain letters and _',
8353 * The keystroke filter mask to be applied on alpha input
8356 'alphaMask' : /[a-z_]/i,
8359 * The function used to validate alphanumeric values
8360 * @param {String} value The value
8362 'alphanum' : function(v){
8363 return alphanum.test(v);
8366 * The error text to display when the alphanumeric validation function returns false
8369 'alphanumText' : 'This field should only contain letters, numbers and _',
8371 * The keystroke filter mask to be applied on alphanumeric input
8374 'alphanumMask' : /[a-z0-9_]/i
8384 * @class Roo.bootstrap.Input
8385 * @extends Roo.bootstrap.Component
8386 * Bootstrap Input class
8387 * @cfg {Boolean} disabled is it disabled
8388 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8389 * @cfg {String} name name of the input
8390 * @cfg {string} fieldLabel - the label associated
8391 * @cfg {string} placeholder - placeholder to put in text.
8392 * @cfg {string} before - input group add on before
8393 * @cfg {string} after - input group add on after
8394 * @cfg {string} size - (lg|sm) or leave empty..
8395 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8396 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8397 * @cfg {Number} md colspan out of 12 for computer-sized screens
8398 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8399 * @cfg {string} value default value of the input
8400 * @cfg {Number} labelWidth set the width of label
8401 * @cfg {Number} labellg set the width of label (1-12)
8402 * @cfg {Number} labelmd set the width of label (1-12)
8403 * @cfg {Number} labelsm set the width of label (1-12)
8404 * @cfg {Number} labelxs set the width of label (1-12)
8405 * @cfg {String} labelAlign (top|left)
8406 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8407 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8408 * @cfg {String} indicatorpos (left|right) default left
8410 * @cfg {String} align (left|center|right) Default left
8411 * @cfg {Boolean} forceFeedback (true|false) Default false
8417 * Create a new Input
8418 * @param {Object} config The config object
8421 Roo.bootstrap.Input = function(config){
8423 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8428 * Fires when this field receives input focus.
8429 * @param {Roo.form.Field} this
8434 * Fires when this field loses input focus.
8435 * @param {Roo.form.Field} this
8440 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8441 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8442 * @param {Roo.form.Field} this
8443 * @param {Roo.EventObject} e The event object
8448 * Fires just before the field blurs if the field value has changed.
8449 * @param {Roo.form.Field} this
8450 * @param {Mixed} newValue The new value
8451 * @param {Mixed} oldValue The original value
8456 * Fires after the field has been marked as invalid.
8457 * @param {Roo.form.Field} this
8458 * @param {String} msg The validation message
8463 * Fires after the field has been validated with no errors.
8464 * @param {Roo.form.Field} this
8469 * Fires after the key up
8470 * @param {Roo.form.Field} this
8471 * @param {Roo.EventObject} e The event Object
8477 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8479 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8480 automatic validation (defaults to "keyup").
8482 validationEvent : "keyup",
8484 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8486 validateOnBlur : true,
8488 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8490 validationDelay : 250,
8492 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8494 focusClass : "x-form-focus", // not needed???
8498 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8500 invalidClass : "has-warning",
8503 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8505 validClass : "has-success",
8508 * @cfg {Boolean} hasFeedback (true|false) default true
8513 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8515 invalidFeedbackClass : "glyphicon-warning-sign",
8518 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8520 validFeedbackClass : "glyphicon-ok",
8523 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8525 selectOnFocus : false,
8528 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8532 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8537 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8539 disableKeyFilter : false,
8542 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8546 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8550 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8552 blankText : "Please complete this mandatory field",
8555 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8559 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8561 maxLength : Number.MAX_VALUE,
8563 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8565 minLengthText : "The minimum length for this field is {0}",
8567 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8569 maxLengthText : "The maximum length for this field is {0}",
8573 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8574 * If available, this function will be called only after the basic validators all return true, and will be passed the
8575 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8579 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8580 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8581 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8585 * @cfg {String} regexText -- Depricated - use Invalid Text
8590 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8596 autocomplete: false,
8615 formatedValue : false,
8616 forceFeedback : false,
8618 indicatorpos : 'left',
8625 parentLabelAlign : function()
8628 while (parent.parent()) {
8629 parent = parent.parent();
8630 if (typeof(parent.labelAlign) !='undefined') {
8631 return parent.labelAlign;
8638 getAutoCreate : function()
8640 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8646 if(this.inputType != 'hidden'){
8647 cfg.cls = 'form-group' //input-group
8653 type : this.inputType,
8655 cls : 'form-control',
8656 placeholder : this.placeholder || '',
8657 autocomplete : this.autocomplete || 'new-password'
8661 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8664 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8665 input.maxLength = this.maxLength;
8668 if (this.disabled) {
8669 input.disabled=true;
8672 if (this.readOnly) {
8673 input.readonly=true;
8677 input.name = this.name;
8681 input.cls += ' input-' + this.size;
8685 ['xs','sm','md','lg'].map(function(size){
8686 if (settings[size]) {
8687 cfg.cls += ' col-' + size + '-' + settings[size];
8691 var inputblock = input;
8695 cls: 'glyphicon form-control-feedback'
8698 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8701 cls : 'has-feedback',
8709 if (this.before || this.after) {
8712 cls : 'input-group',
8716 if (this.before && typeof(this.before) == 'string') {
8718 inputblock.cn.push({
8720 cls : 'roo-input-before input-group-addon',
8724 if (this.before && typeof(this.before) == 'object') {
8725 this.before = Roo.factory(this.before);
8727 inputblock.cn.push({
8729 cls : 'roo-input-before input-group-' +
8730 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8734 inputblock.cn.push(input);
8736 if (this.after && typeof(this.after) == 'string') {
8737 inputblock.cn.push({
8739 cls : 'roo-input-after input-group-addon',
8743 if (this.after && typeof(this.after) == 'object') {
8744 this.after = Roo.factory(this.after);
8746 inputblock.cn.push({
8748 cls : 'roo-input-after input-group-' +
8749 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8753 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8754 inputblock.cls += ' has-feedback';
8755 inputblock.cn.push(feedback);
8759 if (align ==='left' && this.fieldLabel.length) {
8761 cfg.cls += ' roo-form-group-label-left';
8766 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8767 tooltip : 'This field is required'
8772 cls : 'control-label',
8773 html : this.fieldLabel
8784 var labelCfg = cfg.cn[1];
8785 var contentCfg = cfg.cn[2];
8787 if(this.indicatorpos == 'right'){
8792 cls : 'control-label',
8796 html : this.fieldLabel
8800 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8801 tooltip : 'This field is required'
8814 labelCfg = cfg.cn[0];
8815 contentCfg = cfg.cn[1];
8819 if(this.labelWidth > 12){
8820 labelCfg.style = "width: " + this.labelWidth + 'px';
8823 if(this.labelWidth < 13 && this.labelmd == 0){
8824 this.labelmd = this.labelWidth;
8827 if(this.labellg > 0){
8828 labelCfg.cls += ' col-lg-' + this.labellg;
8829 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8832 if(this.labelmd > 0){
8833 labelCfg.cls += ' col-md-' + this.labelmd;
8834 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8837 if(this.labelsm > 0){
8838 labelCfg.cls += ' col-sm-' + this.labelsm;
8839 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8842 if(this.labelxs > 0){
8843 labelCfg.cls += ' col-xs-' + this.labelxs;
8844 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8848 } else if ( this.fieldLabel.length) {
8853 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8854 tooltip : 'This field is required'
8858 //cls : 'input-group-addon',
8859 html : this.fieldLabel
8867 if(this.indicatorpos == 'right'){
8872 //cls : 'input-group-addon',
8873 html : this.fieldLabel
8878 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8879 tooltip : 'This field is required'
8899 if (this.parentType === 'Navbar' && this.parent().bar) {
8900 cfg.cls += ' navbar-form';
8903 if (this.parentType === 'NavGroup') {
8904 cfg.cls += ' navbar-form';
8912 * return the real input element.
8914 inputEl: function ()
8916 return this.el.select('input.form-control',true).first();
8919 tooltipEl : function()
8921 return this.inputEl();
8924 indicatorEl : function()
8926 var indicator = this.el.select('i.roo-required-indicator',true).first();
8936 setDisabled : function(v)
8938 var i = this.inputEl().dom;
8940 i.removeAttribute('disabled');
8944 i.setAttribute('disabled','true');
8946 initEvents : function()
8949 this.inputEl().on("keydown" , this.fireKey, this);
8950 this.inputEl().on("focus", this.onFocus, this);
8951 this.inputEl().on("blur", this.onBlur, this);
8953 this.inputEl().relayEvent('keyup', this);
8955 this.indicator = this.indicatorEl();
8958 this.indicator.addClass('invisible');
8962 // reference to original value for reset
8963 this.originalValue = this.getValue();
8964 //Roo.form.TextField.superclass.initEvents.call(this);
8965 if(this.validationEvent == 'keyup'){
8966 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8967 this.inputEl().on('keyup', this.filterValidation, this);
8969 else if(this.validationEvent !== false){
8970 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8973 if(this.selectOnFocus){
8974 this.on("focus", this.preFocus, this);
8977 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8978 this.inputEl().on("keypress", this.filterKeys, this);
8980 this.inputEl().relayEvent('keypress', this);
8983 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8984 this.el.on("click", this.autoSize, this);
8987 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8988 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8991 if (typeof(this.before) == 'object') {
8992 this.before.render(this.el.select('.roo-input-before',true).first());
8994 if (typeof(this.after) == 'object') {
8995 this.after.render(this.el.select('.roo-input-after',true).first());
9000 filterValidation : function(e){
9001 if(!e.isNavKeyPress()){
9002 this.validationTask.delay(this.validationDelay);
9006 * Validates the field value
9007 * @return {Boolean} True if the value is valid, else false
9009 validate : function(){
9010 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9011 if(this.disabled || this.validateValue(this.getRawValue())){
9022 * Validates a value according to the field's validation rules and marks the field as invalid
9023 * if the validation fails
9024 * @param {Mixed} value The value to validate
9025 * @return {Boolean} True if the value is valid, else false
9027 validateValue : function(value){
9028 if(value.length < 1) { // if it's blank
9029 if(this.allowBlank){
9032 return this.inputEl().hasClass('hide') ? true : false;
9035 if(value.length < this.minLength){
9038 if(value.length > this.maxLength){
9042 var vt = Roo.form.VTypes;
9043 if(!vt[this.vtype](value, this)){
9047 if(typeof this.validator == "function"){
9048 var msg = this.validator(value);
9052 if (typeof(msg) == 'string') {
9053 this.invalidText = msg;
9057 if(this.regex && !this.regex.test(value)){
9067 fireKey : function(e){
9068 //Roo.log('field ' + e.getKey());
9069 if(e.isNavKeyPress()){
9070 this.fireEvent("specialkey", this, e);
9073 focus : function (selectText){
9075 this.inputEl().focus();
9076 if(selectText === true){
9077 this.inputEl().dom.select();
9083 onFocus : function(){
9084 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9085 // this.el.addClass(this.focusClass);
9088 this.hasFocus = true;
9089 this.startValue = this.getValue();
9090 this.fireEvent("focus", this);
9094 beforeBlur : Roo.emptyFn,
9098 onBlur : function(){
9100 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9101 //this.el.removeClass(this.focusClass);
9103 this.hasFocus = false;
9104 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9107 var v = this.getValue();
9108 if(String(v) !== String(this.startValue)){
9109 this.fireEvent('change', this, v, this.startValue);
9111 this.fireEvent("blur", this);
9115 * Resets the current field value to the originally loaded value and clears any validation messages
9118 this.setValue(this.originalValue);
9122 * Returns the name of the field
9123 * @return {Mixed} name The name field
9125 getName: function(){
9129 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9130 * @return {Mixed} value The field value
9132 getValue : function(){
9134 var v = this.inputEl().getValue();
9139 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9140 * @return {Mixed} value The field value
9142 getRawValue : function(){
9143 var v = this.inputEl().getValue();
9149 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9150 * @param {Mixed} value The value to set
9152 setRawValue : function(v){
9153 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9156 selectText : function(start, end){
9157 var v = this.getRawValue();
9159 start = start === undefined ? 0 : start;
9160 end = end === undefined ? v.length : end;
9161 var d = this.inputEl().dom;
9162 if(d.setSelectionRange){
9163 d.setSelectionRange(start, end);
9164 }else if(d.createTextRange){
9165 var range = d.createTextRange();
9166 range.moveStart("character", start);
9167 range.moveEnd("character", v.length-end);
9174 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9175 * @param {Mixed} value The value to set
9177 setValue : function(v){
9180 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9186 processValue : function(value){
9187 if(this.stripCharsRe){
9188 var newValue = value.replace(this.stripCharsRe, '');
9189 if(newValue !== value){
9190 this.setRawValue(newValue);
9197 preFocus : function(){
9199 if(this.selectOnFocus){
9200 this.inputEl().dom.select();
9203 filterKeys : function(e){
9205 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9208 var c = e.getCharCode(), cc = String.fromCharCode(c);
9209 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9212 if(!this.maskRe.test(cc)){
9217 * Clear any invalid styles/messages for this field
9219 clearInvalid : function(){
9221 if(!this.el || this.preventMark){ // not rendered
9226 this.el.removeClass(this.invalidClass);
9228 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9230 var feedback = this.el.select('.form-control-feedback', true).first();
9233 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9238 this.fireEvent('valid', this);
9242 * Mark this field as valid
9244 markValid : function()
9246 if(!this.el || this.preventMark){ // not rendered...
9250 this.el.removeClass([this.invalidClass, this.validClass]);
9252 var feedback = this.el.select('.form-control-feedback', true).first();
9255 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9262 if(this.allowBlank && !this.getRawValue().length){
9267 this.indicator.removeClass('visible');
9268 this.indicator.addClass('invisible');
9271 this.el.addClass(this.validClass);
9273 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9275 var feedback = this.el.select('.form-control-feedback', true).first();
9278 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9279 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9284 this.fireEvent('valid', this);
9288 * Mark this field as invalid
9289 * @param {String} msg The validation message
9291 markInvalid : function(msg)
9293 if(!this.el || this.preventMark){ // not rendered
9297 this.el.removeClass([this.invalidClass, this.validClass]);
9299 var feedback = this.el.select('.form-control-feedback', true).first();
9302 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9309 if(this.allowBlank && !this.getRawValue().length){
9314 this.indicator.removeClass('invisible');
9315 this.indicator.addClass('visible');
9318 this.el.addClass(this.invalidClass);
9320 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9322 var feedback = this.el.select('.form-control-feedback', true).first();
9325 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9327 if(this.getValue().length || this.forceFeedback){
9328 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9335 this.fireEvent('invalid', this, msg);
9338 SafariOnKeyDown : function(event)
9340 // this is a workaround for a password hang bug on chrome/ webkit.
9341 if (this.inputEl().dom.type != 'password') {
9345 var isSelectAll = false;
9347 if(this.inputEl().dom.selectionEnd > 0){
9348 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9350 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9351 event.preventDefault();
9356 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9358 event.preventDefault();
9359 // this is very hacky as keydown always get's upper case.
9361 var cc = String.fromCharCode(event.getCharCode());
9362 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9366 adjustWidth : function(tag, w){
9367 tag = tag.toLowerCase();
9368 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9369 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9373 if(tag == 'textarea'){
9376 }else if(Roo.isOpera){
9380 if(tag == 'textarea'){
9388 setFieldLabel : function(v)
9394 this.fieldLabel = v;
9397 var ar = this.el.select('label > span',true);
9398 if (!ar.elements.length) {
9399 Roo.log("could not find label > span on element");
9403 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9407 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9420 * @class Roo.bootstrap.TextArea
9421 * @extends Roo.bootstrap.Input
9422 * Bootstrap TextArea class
9423 * @cfg {Number} cols Specifies the visible width of a text area
9424 * @cfg {Number} rows Specifies the visible number of lines in a text area
9425 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9426 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9427 * @cfg {string} html text
9430 * Create a new TextArea
9431 * @param {Object} config The config object
9434 Roo.bootstrap.TextArea = function(config){
9435 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9439 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9449 getAutoCreate : function(){
9451 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9457 if(this.inputType != 'hidden'){
9458 cfg.cls = 'form-group' //input-group
9466 value : this.value || '',
9467 html: this.html || '',
9468 cls : 'form-control',
9469 placeholder : this.placeholder || ''
9473 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9474 input.maxLength = this.maxLength;
9478 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9482 input.cols = this.cols;
9485 if (this.readOnly) {
9486 input.readonly = true;
9490 input.name = this.name;
9494 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9498 ['xs','sm','md','lg'].map(function(size){
9499 if (settings[size]) {
9500 cfg.cls += ' col-' + size + '-' + settings[size];
9504 var inputblock = input;
9506 if(this.hasFeedback && !this.allowBlank){
9510 cls: 'glyphicon form-control-feedback'
9514 cls : 'has-feedback',
9523 if (this.before || this.after) {
9526 cls : 'input-group',
9530 inputblock.cn.push({
9532 cls : 'input-group-addon',
9537 inputblock.cn.push(input);
9539 if(this.hasFeedback && !this.allowBlank){
9540 inputblock.cls += ' has-feedback';
9541 inputblock.cn.push(feedback);
9545 inputblock.cn.push({
9547 cls : 'input-group-addon',
9554 if (align ==='left' && this.fieldLabel.length) {
9559 cls : 'control-label',
9560 html : this.fieldLabel
9571 if(this.labelWidth > 12){
9572 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9575 if(this.labelWidth < 13 && this.labelmd == 0){
9576 this.labelmd = this.labelWidth;
9579 if(this.labellg > 0){
9580 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9581 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9584 if(this.labelmd > 0){
9585 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9586 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9589 if(this.labelsm > 0){
9590 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9591 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9594 if(this.labelxs > 0){
9595 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9596 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9599 } else if ( this.fieldLabel.length) {
9604 //cls : 'input-group-addon',
9605 html : this.fieldLabel
9623 if (this.disabled) {
9624 input.disabled=true;
9631 * return the real textarea element.
9633 inputEl: function ()
9635 return this.el.select('textarea.form-control',true).first();
9639 * Clear any invalid styles/messages for this field
9641 clearInvalid : function()
9644 if(!this.el || this.preventMark){ // not rendered
9648 var label = this.el.select('label', true).first();
9649 var icon = this.el.select('i.fa-star', true).first();
9655 this.el.removeClass(this.invalidClass);
9657 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9659 var feedback = this.el.select('.form-control-feedback', true).first();
9662 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9667 this.fireEvent('valid', this);
9671 * Mark this field as valid
9673 markValid : function()
9675 if(!this.el || this.preventMark){ // not rendered
9679 this.el.removeClass([this.invalidClass, this.validClass]);
9681 var feedback = this.el.select('.form-control-feedback', true).first();
9684 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9687 if(this.disabled || this.allowBlank){
9691 var label = this.el.select('label', true).first();
9692 var icon = this.el.select('i.fa-star', true).first();
9698 this.el.addClass(this.validClass);
9700 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9702 var feedback = this.el.select('.form-control-feedback', true).first();
9705 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9706 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9711 this.fireEvent('valid', this);
9715 * Mark this field as invalid
9716 * @param {String} msg The validation message
9718 markInvalid : function(msg)
9720 if(!this.el || this.preventMark){ // not rendered
9724 this.el.removeClass([this.invalidClass, this.validClass]);
9726 var feedback = this.el.select('.form-control-feedback', true).first();
9729 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9732 if(this.disabled || this.allowBlank){
9736 var label = this.el.select('label', true).first();
9737 var icon = this.el.select('i.fa-star', true).first();
9739 if(!this.getValue().length && label && !icon){
9740 this.el.createChild({
9742 cls : 'text-danger fa fa-lg fa-star',
9743 tooltip : 'This field is required',
9744 style : 'margin-right:5px;'
9748 this.el.addClass(this.invalidClass);
9750 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9752 var feedback = this.el.select('.form-control-feedback', true).first();
9755 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9757 if(this.getValue().length || this.forceFeedback){
9758 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9765 this.fireEvent('invalid', this, msg);
9773 * trigger field - base class for combo..
9778 * @class Roo.bootstrap.TriggerField
9779 * @extends Roo.bootstrap.Input
9780 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9781 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9782 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9783 * for which you can provide a custom implementation. For example:
9785 var trigger = new Roo.bootstrap.TriggerField();
9786 trigger.onTriggerClick = myTriggerFn;
9787 trigger.applyTo('my-field');
9790 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9791 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9792 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9793 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9794 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9797 * Create a new TriggerField.
9798 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9799 * to the base TextField)
9801 Roo.bootstrap.TriggerField = function(config){
9802 this.mimicing = false;
9803 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9806 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9808 * @cfg {String} triggerClass A CSS class to apply to the trigger
9811 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9816 * @cfg {Boolean} removable (true|false) special filter default false
9820 /** @cfg {Boolean} grow @hide */
9821 /** @cfg {Number} growMin @hide */
9822 /** @cfg {Number} growMax @hide */
9828 autoSize: Roo.emptyFn,
9835 actionMode : 'wrap',
9840 getAutoCreate : function(){
9842 var align = this.labelAlign || this.parentLabelAlign();
9847 cls: 'form-group' //input-group
9854 type : this.inputType,
9855 cls : 'form-control',
9856 autocomplete: 'new-password',
9857 placeholder : this.placeholder || ''
9861 input.name = this.name;
9864 input.cls += ' input-' + this.size;
9867 if (this.disabled) {
9868 input.disabled=true;
9871 var inputblock = input;
9873 if(this.hasFeedback && !this.allowBlank){
9877 cls: 'glyphicon form-control-feedback'
9880 if(this.removable && !this.editable && !this.tickable){
9882 cls : 'has-feedback',
9888 cls : 'roo-combo-removable-btn close'
9895 cls : 'has-feedback',
9904 if(this.removable && !this.editable && !this.tickable){
9906 cls : 'roo-removable',
9912 cls : 'roo-combo-removable-btn close'
9919 if (this.before || this.after) {
9922 cls : 'input-group',
9926 inputblock.cn.push({
9928 cls : 'input-group-addon',
9933 inputblock.cn.push(input);
9935 if(this.hasFeedback && !this.allowBlank){
9936 inputblock.cls += ' has-feedback';
9937 inputblock.cn.push(feedback);
9941 inputblock.cn.push({
9943 cls : 'input-group-addon',
9956 cls: 'form-hidden-field'
9970 cls: 'form-hidden-field'
9974 cls: 'roo-select2-choices',
9978 cls: 'roo-select2-search-field',
9991 cls: 'roo-select2-container input-group',
9996 // cls: 'typeahead typeahead-long dropdown-menu',
9997 // style: 'display:none'
10002 if(!this.multiple && this.showToggleBtn){
10008 if (this.caret != false) {
10011 cls: 'fa fa-' + this.caret
10018 cls : 'input-group-addon btn dropdown-toggle',
10023 cls: 'combobox-clear',
10037 combobox.cls += ' roo-select2-container-multi';
10040 if (align ==='left' && this.fieldLabel.length) {
10042 cfg.cls += ' roo-form-group-label-left';
10047 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10048 tooltip : 'This field is required'
10053 cls : 'control-label',
10054 html : this.fieldLabel
10066 var labelCfg = cfg.cn[1];
10067 var contentCfg = cfg.cn[2];
10069 if(this.indicatorpos == 'right'){
10074 cls : 'control-label',
10078 html : this.fieldLabel
10082 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10083 tooltip : 'This field is required'
10096 labelCfg = cfg.cn[0];
10097 contentCfg = cfg.cn[1];
10100 if(this.labelWidth > 12){
10101 labelCfg.style = "width: " + this.labelWidth + 'px';
10104 if(this.labelWidth < 13 && this.labelmd == 0){
10105 this.labelmd = this.labelWidth;
10108 if(this.labellg > 0){
10109 labelCfg.cls += ' col-lg-' + this.labellg;
10110 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10113 if(this.labelmd > 0){
10114 labelCfg.cls += ' col-md-' + this.labelmd;
10115 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10118 if(this.labelsm > 0){
10119 labelCfg.cls += ' col-sm-' + this.labelsm;
10120 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10123 if(this.labelxs > 0){
10124 labelCfg.cls += ' col-xs-' + this.labelxs;
10125 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10128 } else if ( this.fieldLabel.length) {
10129 // Roo.log(" label");
10133 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10134 tooltip : 'This field is required'
10138 //cls : 'input-group-addon',
10139 html : this.fieldLabel
10147 if(this.indicatorpos == 'right'){
10155 html : this.fieldLabel
10159 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10160 tooltip : 'This field is required'
10173 // Roo.log(" no label && no align");
10180 ['xs','sm','md','lg'].map(function(size){
10181 if (settings[size]) {
10182 cfg.cls += ' col-' + size + '-' + settings[size];
10193 onResize : function(w, h){
10194 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10195 // if(typeof w == 'number'){
10196 // var x = w - this.trigger.getWidth();
10197 // this.inputEl().setWidth(this.adjustWidth('input', x));
10198 // this.trigger.setStyle('left', x+'px');
10203 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10206 getResizeEl : function(){
10207 return this.inputEl();
10211 getPositionEl : function(){
10212 return this.inputEl();
10216 alignErrorIcon : function(){
10217 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10221 initEvents : function(){
10225 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10226 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10227 if(!this.multiple && this.showToggleBtn){
10228 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10229 if(this.hideTrigger){
10230 this.trigger.setDisplayed(false);
10232 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10236 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10239 if(this.removable && !this.editable && !this.tickable){
10240 var close = this.closeTriggerEl();
10243 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10244 close.on('click', this.removeBtnClick, this, close);
10248 //this.trigger.addClassOnOver('x-form-trigger-over');
10249 //this.trigger.addClassOnClick('x-form-trigger-click');
10252 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10256 closeTriggerEl : function()
10258 var close = this.el.select('.roo-combo-removable-btn', true).first();
10259 return close ? close : false;
10262 removeBtnClick : function(e, h, el)
10264 e.preventDefault();
10266 if(this.fireEvent("remove", this) !== false){
10268 this.fireEvent("afterremove", this)
10272 createList : function()
10274 this.list = Roo.get(document.body).createChild({
10276 cls: 'typeahead typeahead-long dropdown-menu',
10277 style: 'display:none'
10280 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10285 initTrigger : function(){
10290 onDestroy : function(){
10292 this.trigger.removeAllListeners();
10293 // this.trigger.remove();
10296 // this.wrap.remove();
10298 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10302 onFocus : function(){
10303 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10305 if(!this.mimicing){
10306 this.wrap.addClass('x-trigger-wrap-focus');
10307 this.mimicing = true;
10308 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10309 if(this.monitorTab){
10310 this.el.on("keydown", this.checkTab, this);
10317 checkTab : function(e){
10318 if(e.getKey() == e.TAB){
10319 this.triggerBlur();
10324 onBlur : function(){
10329 mimicBlur : function(e, t){
10331 if(!this.wrap.contains(t) && this.validateBlur()){
10332 this.triggerBlur();
10338 triggerBlur : function(){
10339 this.mimicing = false;
10340 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10341 if(this.monitorTab){
10342 this.el.un("keydown", this.checkTab, this);
10344 //this.wrap.removeClass('x-trigger-wrap-focus');
10345 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10349 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10350 validateBlur : function(e, t){
10355 onDisable : function(){
10356 this.inputEl().dom.disabled = true;
10357 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10359 // this.wrap.addClass('x-item-disabled');
10364 onEnable : function(){
10365 this.inputEl().dom.disabled = false;
10366 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10368 // this.el.removeClass('x-item-disabled');
10373 onShow : function(){
10374 var ae = this.getActionEl();
10377 ae.dom.style.display = '';
10378 ae.dom.style.visibility = 'visible';
10384 onHide : function(){
10385 var ae = this.getActionEl();
10386 ae.dom.style.display = 'none';
10390 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10391 * by an implementing function.
10393 * @param {EventObject} e
10395 onTriggerClick : Roo.emptyFn
10399 * Ext JS Library 1.1.1
10400 * Copyright(c) 2006-2007, Ext JS, LLC.
10402 * Originally Released Under LGPL - original licence link has changed is not relivant.
10405 * <script type="text/javascript">
10410 * @class Roo.data.SortTypes
10412 * Defines the default sorting (casting?) comparison functions used when sorting data.
10414 Roo.data.SortTypes = {
10416 * Default sort that does nothing
10417 * @param {Mixed} s The value being converted
10418 * @return {Mixed} The comparison value
10420 none : function(s){
10425 * The regular expression used to strip tags
10429 stripTagsRE : /<\/?[^>]+>/gi,
10432 * Strips all HTML tags to sort on text only
10433 * @param {Mixed} s The value being converted
10434 * @return {String} The comparison value
10436 asText : function(s){
10437 return String(s).replace(this.stripTagsRE, "");
10441 * Strips all HTML tags to sort on text only - Case insensitive
10442 * @param {Mixed} s The value being converted
10443 * @return {String} The comparison value
10445 asUCText : function(s){
10446 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10450 * Case insensitive string
10451 * @param {Mixed} s The value being converted
10452 * @return {String} The comparison value
10454 asUCString : function(s) {
10455 return String(s).toUpperCase();
10460 * @param {Mixed} s The value being converted
10461 * @return {Number} The comparison value
10463 asDate : function(s) {
10467 if(s instanceof Date){
10468 return s.getTime();
10470 return Date.parse(String(s));
10475 * @param {Mixed} s The value being converted
10476 * @return {Float} The comparison value
10478 asFloat : function(s) {
10479 var val = parseFloat(String(s).replace(/,/g, ""));
10488 * @param {Mixed} s The value being converted
10489 * @return {Number} The comparison value
10491 asInt : function(s) {
10492 var val = parseInt(String(s).replace(/,/g, ""));
10500 * Ext JS Library 1.1.1
10501 * Copyright(c) 2006-2007, Ext JS, LLC.
10503 * Originally Released Under LGPL - original licence link has changed is not relivant.
10506 * <script type="text/javascript">
10510 * @class Roo.data.Record
10511 * Instances of this class encapsulate both record <em>definition</em> information, and record
10512 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10513 * to access Records cached in an {@link Roo.data.Store} object.<br>
10515 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10516 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10519 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10521 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10522 * {@link #create}. The parameters are the same.
10523 * @param {Array} data An associative Array of data values keyed by the field name.
10524 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10525 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10526 * not specified an integer id is generated.
10528 Roo.data.Record = function(data, id){
10529 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10534 * Generate a constructor for a specific record layout.
10535 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10536 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10537 * Each field definition object may contain the following properties: <ul>
10538 * <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,
10539 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10540 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10541 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10542 * is being used, then this is a string containing the javascript expression to reference the data relative to
10543 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10544 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10545 * this may be omitted.</p></li>
10546 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10547 * <ul><li>auto (Default, implies no conversion)</li>
10552 * <li>date</li></ul></p></li>
10553 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10554 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10555 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10556 * by the Reader into an object that will be stored in the Record. It is passed the
10557 * following parameters:<ul>
10558 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10560 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10562 * <br>usage:<br><pre><code>
10563 var TopicRecord = Roo.data.Record.create(
10564 {name: 'title', mapping: 'topic_title'},
10565 {name: 'author', mapping: 'username'},
10566 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10567 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10568 {name: 'lastPoster', mapping: 'user2'},
10569 {name: 'excerpt', mapping: 'post_text'}
10572 var myNewRecord = new TopicRecord({
10573 title: 'Do my job please',
10576 lastPost: new Date(),
10577 lastPoster: 'Animal',
10578 excerpt: 'No way dude!'
10580 myStore.add(myNewRecord);
10585 Roo.data.Record.create = function(o){
10586 var f = function(){
10587 f.superclass.constructor.apply(this, arguments);
10589 Roo.extend(f, Roo.data.Record);
10590 var p = f.prototype;
10591 p.fields = new Roo.util.MixedCollection(false, function(field){
10594 for(var i = 0, len = o.length; i < len; i++){
10595 p.fields.add(new Roo.data.Field(o[i]));
10597 f.getField = function(name){
10598 return p.fields.get(name);
10603 Roo.data.Record.AUTO_ID = 1000;
10604 Roo.data.Record.EDIT = 'edit';
10605 Roo.data.Record.REJECT = 'reject';
10606 Roo.data.Record.COMMIT = 'commit';
10608 Roo.data.Record.prototype = {
10610 * Readonly flag - true if this record has been modified.
10619 join : function(store){
10620 this.store = store;
10624 * Set the named field to the specified value.
10625 * @param {String} name The name of the field to set.
10626 * @param {Object} value The value to set the field to.
10628 set : function(name, value){
10629 if(this.data[name] == value){
10633 if(!this.modified){
10634 this.modified = {};
10636 if(typeof this.modified[name] == 'undefined'){
10637 this.modified[name] = this.data[name];
10639 this.data[name] = value;
10640 if(!this.editing && this.store){
10641 this.store.afterEdit(this);
10646 * Get the value of the named field.
10647 * @param {String} name The name of the field to get the value of.
10648 * @return {Object} The value of the field.
10650 get : function(name){
10651 return this.data[name];
10655 beginEdit : function(){
10656 this.editing = true;
10657 this.modified = {};
10661 cancelEdit : function(){
10662 this.editing = false;
10663 delete this.modified;
10667 endEdit : function(){
10668 this.editing = false;
10669 if(this.dirty && this.store){
10670 this.store.afterEdit(this);
10675 * Usually called by the {@link Roo.data.Store} which owns the Record.
10676 * Rejects all changes made to the Record since either creation, or the last commit operation.
10677 * Modified fields are reverted to their original values.
10679 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10680 * of reject operations.
10682 reject : function(){
10683 var m = this.modified;
10685 if(typeof m[n] != "function"){
10686 this.data[n] = m[n];
10689 this.dirty = false;
10690 delete this.modified;
10691 this.editing = false;
10693 this.store.afterReject(this);
10698 * Usually called by the {@link Roo.data.Store} which owns the Record.
10699 * Commits all changes made to the Record since either creation, or the last commit operation.
10701 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10702 * of commit operations.
10704 commit : function(){
10705 this.dirty = false;
10706 delete this.modified;
10707 this.editing = false;
10709 this.store.afterCommit(this);
10714 hasError : function(){
10715 return this.error != null;
10719 clearError : function(){
10724 * Creates a copy of this record.
10725 * @param {String} id (optional) A new record id if you don't want to use this record's id
10728 copy : function(newId) {
10729 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10733 * Ext JS Library 1.1.1
10734 * Copyright(c) 2006-2007, Ext JS, LLC.
10736 * Originally Released Under LGPL - original licence link has changed is not relivant.
10739 * <script type="text/javascript">
10745 * @class Roo.data.Store
10746 * @extends Roo.util.Observable
10747 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10748 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10750 * 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
10751 * has no knowledge of the format of the data returned by the Proxy.<br>
10753 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10754 * instances from the data object. These records are cached and made available through accessor functions.
10756 * Creates a new Store.
10757 * @param {Object} config A config object containing the objects needed for the Store to access data,
10758 * and read the data into Records.
10760 Roo.data.Store = function(config){
10761 this.data = new Roo.util.MixedCollection(false);
10762 this.data.getKey = function(o){
10765 this.baseParams = {};
10767 this.paramNames = {
10772 "multisort" : "_multisort"
10775 if(config && config.data){
10776 this.inlineData = config.data;
10777 delete config.data;
10780 Roo.apply(this, config);
10782 if(this.reader){ // reader passed
10783 this.reader = Roo.factory(this.reader, Roo.data);
10784 this.reader.xmodule = this.xmodule || false;
10785 if(!this.recordType){
10786 this.recordType = this.reader.recordType;
10788 if(this.reader.onMetaChange){
10789 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10793 if(this.recordType){
10794 this.fields = this.recordType.prototype.fields;
10796 this.modified = [];
10800 * @event datachanged
10801 * Fires when the data cache has changed, and a widget which is using this Store
10802 * as a Record cache should refresh its view.
10803 * @param {Store} this
10805 datachanged : true,
10807 * @event metachange
10808 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10809 * @param {Store} this
10810 * @param {Object} meta The JSON metadata
10815 * Fires when Records have been added to the Store
10816 * @param {Store} this
10817 * @param {Roo.data.Record[]} records The array of Records added
10818 * @param {Number} index The index at which the record(s) were added
10823 * Fires when a Record has been removed from the Store
10824 * @param {Store} this
10825 * @param {Roo.data.Record} record The Record that was removed
10826 * @param {Number} index The index at which the record was removed
10831 * Fires when a Record has been updated
10832 * @param {Store} this
10833 * @param {Roo.data.Record} record The Record that was updated
10834 * @param {String} operation The update operation being performed. Value may be one of:
10836 Roo.data.Record.EDIT
10837 Roo.data.Record.REJECT
10838 Roo.data.Record.COMMIT
10844 * Fires when the data cache has been cleared.
10845 * @param {Store} this
10849 * @event beforeload
10850 * Fires before a request is made for a new data object. If the beforeload handler returns false
10851 * the load action will be canceled.
10852 * @param {Store} this
10853 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10857 * @event beforeloadadd
10858 * Fires after a new set of Records has been loaded.
10859 * @param {Store} this
10860 * @param {Roo.data.Record[]} records The Records that were loaded
10861 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10863 beforeloadadd : true,
10866 * Fires after a new set of Records has been loaded, before they are added to the store.
10867 * @param {Store} this
10868 * @param {Roo.data.Record[]} records The Records that were loaded
10869 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10870 * @params {Object} return from reader
10874 * @event loadexception
10875 * Fires if an exception occurs in the Proxy during loading.
10876 * Called with the signature of the Proxy's "loadexception" event.
10877 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10880 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10881 * @param {Object} load options
10882 * @param {Object} jsonData from your request (normally this contains the Exception)
10884 loadexception : true
10888 this.proxy = Roo.factory(this.proxy, Roo.data);
10889 this.proxy.xmodule = this.xmodule || false;
10890 this.relayEvents(this.proxy, ["loadexception"]);
10892 this.sortToggle = {};
10893 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10895 Roo.data.Store.superclass.constructor.call(this);
10897 if(this.inlineData){
10898 this.loadData(this.inlineData);
10899 delete this.inlineData;
10903 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10905 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10906 * without a remote query - used by combo/forms at present.
10910 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10913 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10916 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10917 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10920 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10921 * on any HTTP request
10924 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10927 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10931 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10932 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10934 remoteSort : false,
10937 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10938 * loaded or when a record is removed. (defaults to false).
10940 pruneModifiedRecords : false,
10943 lastOptions : null,
10946 * Add Records to the Store and fires the add event.
10947 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10949 add : function(records){
10950 records = [].concat(records);
10951 for(var i = 0, len = records.length; i < len; i++){
10952 records[i].join(this);
10954 var index = this.data.length;
10955 this.data.addAll(records);
10956 this.fireEvent("add", this, records, index);
10960 * Remove a Record from the Store and fires the remove event.
10961 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10963 remove : function(record){
10964 var index = this.data.indexOf(record);
10965 this.data.removeAt(index);
10966 if(this.pruneModifiedRecords){
10967 this.modified.remove(record);
10969 this.fireEvent("remove", this, record, index);
10973 * Remove all Records from the Store and fires the clear event.
10975 removeAll : function(){
10977 if(this.pruneModifiedRecords){
10978 this.modified = [];
10980 this.fireEvent("clear", this);
10984 * Inserts Records to the Store at the given index and fires the add event.
10985 * @param {Number} index The start index at which to insert the passed Records.
10986 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10988 insert : function(index, records){
10989 records = [].concat(records);
10990 for(var i = 0, len = records.length; i < len; i++){
10991 this.data.insert(index, records[i]);
10992 records[i].join(this);
10994 this.fireEvent("add", this, records, index);
10998 * Get the index within the cache of the passed Record.
10999 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11000 * @return {Number} The index of the passed Record. Returns -1 if not found.
11002 indexOf : function(record){
11003 return this.data.indexOf(record);
11007 * Get the index within the cache of the Record with the passed id.
11008 * @param {String} id The id of the Record to find.
11009 * @return {Number} The index of the Record. Returns -1 if not found.
11011 indexOfId : function(id){
11012 return this.data.indexOfKey(id);
11016 * Get the Record with the specified id.
11017 * @param {String} id The id of the Record to find.
11018 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11020 getById : function(id){
11021 return this.data.key(id);
11025 * Get the Record at the specified index.
11026 * @param {Number} index The index of the Record to find.
11027 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11029 getAt : function(index){
11030 return this.data.itemAt(index);
11034 * Returns a range of Records between specified indices.
11035 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11036 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11037 * @return {Roo.data.Record[]} An array of Records
11039 getRange : function(start, end){
11040 return this.data.getRange(start, end);
11044 storeOptions : function(o){
11045 o = Roo.apply({}, o);
11048 this.lastOptions = o;
11052 * Loads the Record cache from the configured Proxy using the configured Reader.
11054 * If using remote paging, then the first load call must specify the <em>start</em>
11055 * and <em>limit</em> properties in the options.params property to establish the initial
11056 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11058 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11059 * and this call will return before the new data has been loaded. Perform any post-processing
11060 * in a callback function, or in a "load" event handler.</strong>
11062 * @param {Object} options An object containing properties which control loading options:<ul>
11063 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11064 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11065 * passed the following arguments:<ul>
11066 * <li>r : Roo.data.Record[]</li>
11067 * <li>options: Options object from the load call</li>
11068 * <li>success: Boolean success indicator</li></ul></li>
11069 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11070 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11073 load : function(options){
11074 options = options || {};
11075 if(this.fireEvent("beforeload", this, options) !== false){
11076 this.storeOptions(options);
11077 var p = Roo.apply(options.params || {}, this.baseParams);
11078 // if meta was not loaded from remote source.. try requesting it.
11079 if (!this.reader.metaFromRemote) {
11080 p._requestMeta = 1;
11082 if(this.sortInfo && this.remoteSort){
11083 var pn = this.paramNames;
11084 p[pn["sort"]] = this.sortInfo.field;
11085 p[pn["dir"]] = this.sortInfo.direction;
11087 if (this.multiSort) {
11088 var pn = this.paramNames;
11089 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11092 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11097 * Reloads the Record cache from the configured Proxy using the configured Reader and
11098 * the options from the last load operation performed.
11099 * @param {Object} options (optional) An object containing properties which may override the options
11100 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11101 * the most recently used options are reused).
11103 reload : function(options){
11104 this.load(Roo.applyIf(options||{}, this.lastOptions));
11108 // Called as a callback by the Reader during a load operation.
11109 loadRecords : function(o, options, success){
11110 if(!o || success === false){
11111 if(success !== false){
11112 this.fireEvent("load", this, [], options, o);
11114 if(options.callback){
11115 options.callback.call(options.scope || this, [], options, false);
11119 // if data returned failure - throw an exception.
11120 if (o.success === false) {
11121 // show a message if no listener is registered.
11122 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11123 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11125 // loadmask wil be hooked into this..
11126 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11129 var r = o.records, t = o.totalRecords || r.length;
11131 this.fireEvent("beforeloadadd", this, r, options, o);
11133 if(!options || options.add !== true){
11134 if(this.pruneModifiedRecords){
11135 this.modified = [];
11137 for(var i = 0, len = r.length; i < len; i++){
11141 this.data = this.snapshot;
11142 delete this.snapshot;
11145 this.data.addAll(r);
11146 this.totalLength = t;
11148 this.fireEvent("datachanged", this);
11150 this.totalLength = Math.max(t, this.data.length+r.length);
11154 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11156 var e = new Roo.data.Record({});
11158 e.set(this.parent.displayField, this.parent.emptyTitle);
11159 e.set(this.parent.valueField, '');
11164 this.fireEvent("load", this, r, options, o);
11165 if(options.callback){
11166 options.callback.call(options.scope || this, r, options, true);
11172 * Loads data from a passed data block. A Reader which understands the format of the data
11173 * must have been configured in the constructor.
11174 * @param {Object} data The data block from which to read the Records. The format of the data expected
11175 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11176 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11178 loadData : function(o, append){
11179 var r = this.reader.readRecords(o);
11180 this.loadRecords(r, {add: append}, true);
11184 * Gets the number of cached records.
11186 * <em>If using paging, this may not be the total size of the dataset. If the data object
11187 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11188 * the data set size</em>
11190 getCount : function(){
11191 return this.data.length || 0;
11195 * Gets the total number of records in the dataset as returned by the server.
11197 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11198 * the dataset size</em>
11200 getTotalCount : function(){
11201 return this.totalLength || 0;
11205 * Returns the sort state of the Store as an object with two properties:
11207 field {String} The name of the field by which the Records are sorted
11208 direction {String} The sort order, "ASC" or "DESC"
11211 getSortState : function(){
11212 return this.sortInfo;
11216 applySort : function(){
11217 if(this.sortInfo && !this.remoteSort){
11218 var s = this.sortInfo, f = s.field;
11219 var st = this.fields.get(f).sortType;
11220 var fn = function(r1, r2){
11221 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11222 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11224 this.data.sort(s.direction, fn);
11225 if(this.snapshot && this.snapshot != this.data){
11226 this.snapshot.sort(s.direction, fn);
11232 * Sets the default sort column and order to be used by the next load operation.
11233 * @param {String} fieldName The name of the field to sort by.
11234 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11236 setDefaultSort : function(field, dir){
11237 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11241 * Sort the Records.
11242 * If remote sorting is used, the sort is performed on the server, and the cache is
11243 * reloaded. If local sorting is used, the cache is sorted internally.
11244 * @param {String} fieldName The name of the field to sort by.
11245 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11247 sort : function(fieldName, dir){
11248 var f = this.fields.get(fieldName);
11250 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11252 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11253 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11258 this.sortToggle[f.name] = dir;
11259 this.sortInfo = {field: f.name, direction: dir};
11260 if(!this.remoteSort){
11262 this.fireEvent("datachanged", this);
11264 this.load(this.lastOptions);
11269 * Calls the specified function for each of the Records in the cache.
11270 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11271 * Returning <em>false</em> aborts and exits the iteration.
11272 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11274 each : function(fn, scope){
11275 this.data.each(fn, scope);
11279 * Gets all records modified since the last commit. Modified records are persisted across load operations
11280 * (e.g., during paging).
11281 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11283 getModifiedRecords : function(){
11284 return this.modified;
11288 createFilterFn : function(property, value, anyMatch){
11289 if(!value.exec){ // not a regex
11290 value = String(value);
11291 if(value.length == 0){
11294 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11296 return function(r){
11297 return value.test(r.data[property]);
11302 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11303 * @param {String} property A field on your records
11304 * @param {Number} start The record index to start at (defaults to 0)
11305 * @param {Number} end The last record index to include (defaults to length - 1)
11306 * @return {Number} The sum
11308 sum : function(property, start, end){
11309 var rs = this.data.items, v = 0;
11310 start = start || 0;
11311 end = (end || end === 0) ? end : rs.length-1;
11313 for(var i = start; i <= end; i++){
11314 v += (rs[i].data[property] || 0);
11320 * Filter the records by a specified property.
11321 * @param {String} field A field on your records
11322 * @param {String/RegExp} value Either a string that the field
11323 * should start with or a RegExp to test against the field
11324 * @param {Boolean} anyMatch True to match any part not just the beginning
11326 filter : function(property, value, anyMatch){
11327 var fn = this.createFilterFn(property, value, anyMatch);
11328 return fn ? this.filterBy(fn) : this.clearFilter();
11332 * Filter by a function. The specified function will be called with each
11333 * record in this data source. If the function returns true the record is included,
11334 * otherwise it is filtered.
11335 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11336 * @param {Object} scope (optional) The scope of the function (defaults to this)
11338 filterBy : function(fn, scope){
11339 this.snapshot = this.snapshot || this.data;
11340 this.data = this.queryBy(fn, scope||this);
11341 this.fireEvent("datachanged", this);
11345 * Query the records by a specified property.
11346 * @param {String} field A field on your records
11347 * @param {String/RegExp} value Either a string that the field
11348 * should start with or a RegExp to test against the field
11349 * @param {Boolean} anyMatch True to match any part not just the beginning
11350 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11352 query : function(property, value, anyMatch){
11353 var fn = this.createFilterFn(property, value, anyMatch);
11354 return fn ? this.queryBy(fn) : this.data.clone();
11358 * Query by a function. The specified function will be called with each
11359 * record in this data source. If the function returns true the record is included
11361 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11362 * @param {Object} scope (optional) The scope of the function (defaults to this)
11363 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11365 queryBy : function(fn, scope){
11366 var data = this.snapshot || this.data;
11367 return data.filterBy(fn, scope||this);
11371 * Collects unique values for a particular dataIndex from this store.
11372 * @param {String} dataIndex The property to collect
11373 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11374 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11375 * @return {Array} An array of the unique values
11377 collect : function(dataIndex, allowNull, bypassFilter){
11378 var d = (bypassFilter === true && this.snapshot) ?
11379 this.snapshot.items : this.data.items;
11380 var v, sv, r = [], l = {};
11381 for(var i = 0, len = d.length; i < len; i++){
11382 v = d[i].data[dataIndex];
11384 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11393 * Revert to a view of the Record cache with no filtering applied.
11394 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11396 clearFilter : function(suppressEvent){
11397 if(this.snapshot && this.snapshot != this.data){
11398 this.data = this.snapshot;
11399 delete this.snapshot;
11400 if(suppressEvent !== true){
11401 this.fireEvent("datachanged", this);
11407 afterEdit : function(record){
11408 if(this.modified.indexOf(record) == -1){
11409 this.modified.push(record);
11411 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11415 afterReject : function(record){
11416 this.modified.remove(record);
11417 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11421 afterCommit : function(record){
11422 this.modified.remove(record);
11423 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11427 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11428 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11430 commitChanges : function(){
11431 var m = this.modified.slice(0);
11432 this.modified = [];
11433 for(var i = 0, len = m.length; i < len; i++){
11439 * Cancel outstanding changes on all changed records.
11441 rejectChanges : function(){
11442 var m = this.modified.slice(0);
11443 this.modified = [];
11444 for(var i = 0, len = m.length; i < len; i++){
11449 onMetaChange : function(meta, rtype, o){
11450 this.recordType = rtype;
11451 this.fields = rtype.prototype.fields;
11452 delete this.snapshot;
11453 this.sortInfo = meta.sortInfo || this.sortInfo;
11454 this.modified = [];
11455 this.fireEvent('metachange', this, this.reader.meta);
11458 moveIndex : function(data, type)
11460 var index = this.indexOf(data);
11462 var newIndex = index + type;
11466 this.insert(newIndex, data);
11471 * Ext JS Library 1.1.1
11472 * Copyright(c) 2006-2007, Ext JS, LLC.
11474 * Originally Released Under LGPL - original licence link has changed is not relivant.
11477 * <script type="text/javascript">
11481 * @class Roo.data.SimpleStore
11482 * @extends Roo.data.Store
11483 * Small helper class to make creating Stores from Array data easier.
11484 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11485 * @cfg {Array} fields An array of field definition objects, or field name strings.
11486 * @cfg {Array} data The multi-dimensional array of data
11488 * @param {Object} config
11490 Roo.data.SimpleStore = function(config){
11491 Roo.data.SimpleStore.superclass.constructor.call(this, {
11493 reader: new Roo.data.ArrayReader({
11496 Roo.data.Record.create(config.fields)
11498 proxy : new Roo.data.MemoryProxy(config.data)
11502 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11504 * Ext JS Library 1.1.1
11505 * Copyright(c) 2006-2007, Ext JS, LLC.
11507 * Originally Released Under LGPL - original licence link has changed is not relivant.
11510 * <script type="text/javascript">
11515 * @extends Roo.data.Store
11516 * @class Roo.data.JsonStore
11517 * Small helper class to make creating Stores for JSON data easier. <br/>
11519 var store = new Roo.data.JsonStore({
11520 url: 'get-images.php',
11522 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11525 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11526 * JsonReader and HttpProxy (unless inline data is provided).</b>
11527 * @cfg {Array} fields An array of field definition objects, or field name strings.
11529 * @param {Object} config
11531 Roo.data.JsonStore = function(c){
11532 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11533 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11534 reader: new Roo.data.JsonReader(c, c.fields)
11537 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11539 * Ext JS Library 1.1.1
11540 * Copyright(c) 2006-2007, Ext JS, LLC.
11542 * Originally Released Under LGPL - original licence link has changed is not relivant.
11545 * <script type="text/javascript">
11549 Roo.data.Field = function(config){
11550 if(typeof config == "string"){
11551 config = {name: config};
11553 Roo.apply(this, config);
11556 this.type = "auto";
11559 var st = Roo.data.SortTypes;
11560 // named sortTypes are supported, here we look them up
11561 if(typeof this.sortType == "string"){
11562 this.sortType = st[this.sortType];
11565 // set default sortType for strings and dates
11566 if(!this.sortType){
11569 this.sortType = st.asUCString;
11572 this.sortType = st.asDate;
11575 this.sortType = st.none;
11580 var stripRe = /[\$,%]/g;
11582 // prebuilt conversion function for this field, instead of
11583 // switching every time we're reading a value
11585 var cv, dateFormat = this.dateFormat;
11590 cv = function(v){ return v; };
11593 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11597 return v !== undefined && v !== null && v !== '' ?
11598 parseInt(String(v).replace(stripRe, ""), 10) : '';
11603 return v !== undefined && v !== null && v !== '' ?
11604 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11609 cv = function(v){ return v === true || v === "true" || v == 1; };
11616 if(v instanceof Date){
11620 if(dateFormat == "timestamp"){
11621 return new Date(v*1000);
11623 return Date.parseDate(v, dateFormat);
11625 var parsed = Date.parse(v);
11626 return parsed ? new Date(parsed) : null;
11635 Roo.data.Field.prototype = {
11643 * Ext JS Library 1.1.1
11644 * Copyright(c) 2006-2007, Ext JS, LLC.
11646 * Originally Released Under LGPL - original licence link has changed is not relivant.
11649 * <script type="text/javascript">
11652 // Base class for reading structured data from a data source. This class is intended to be
11653 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11656 * @class Roo.data.DataReader
11657 * Base class for reading structured data from a data source. This class is intended to be
11658 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11661 Roo.data.DataReader = function(meta, recordType){
11665 this.recordType = recordType instanceof Array ?
11666 Roo.data.Record.create(recordType) : recordType;
11669 Roo.data.DataReader.prototype = {
11671 * Create an empty record
11672 * @param {Object} data (optional) - overlay some values
11673 * @return {Roo.data.Record} record created.
11675 newRow : function(d) {
11677 this.recordType.prototype.fields.each(function(c) {
11679 case 'int' : da[c.name] = 0; break;
11680 case 'date' : da[c.name] = new Date(); break;
11681 case 'float' : da[c.name] = 0.0; break;
11682 case 'boolean' : da[c.name] = false; break;
11683 default : da[c.name] = ""; break;
11687 return new this.recordType(Roo.apply(da, d));
11692 * Ext JS Library 1.1.1
11693 * Copyright(c) 2006-2007, Ext JS, LLC.
11695 * Originally Released Under LGPL - original licence link has changed is not relivant.
11698 * <script type="text/javascript">
11702 * @class Roo.data.DataProxy
11703 * @extends Roo.data.Observable
11704 * This class is an abstract base class for implementations which provide retrieval of
11705 * unformatted data objects.<br>
11707 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11708 * (of the appropriate type which knows how to parse the data object) to provide a block of
11709 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11711 * Custom implementations must implement the load method as described in
11712 * {@link Roo.data.HttpProxy#load}.
11714 Roo.data.DataProxy = function(){
11717 * @event beforeload
11718 * Fires before a network request is made to retrieve a data object.
11719 * @param {Object} This DataProxy object.
11720 * @param {Object} params The params parameter to the load function.
11725 * Fires before the load method's callback is called.
11726 * @param {Object} This DataProxy object.
11727 * @param {Object} o The data object.
11728 * @param {Object} arg The callback argument object passed to the load function.
11732 * @event loadexception
11733 * Fires if an Exception occurs during data retrieval.
11734 * @param {Object} This DataProxy object.
11735 * @param {Object} o The data object.
11736 * @param {Object} arg The callback argument object passed to the load function.
11737 * @param {Object} e The Exception.
11739 loadexception : true
11741 Roo.data.DataProxy.superclass.constructor.call(this);
11744 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11747 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11751 * Ext JS Library 1.1.1
11752 * Copyright(c) 2006-2007, Ext JS, LLC.
11754 * Originally Released Under LGPL - original licence link has changed is not relivant.
11757 * <script type="text/javascript">
11760 * @class Roo.data.MemoryProxy
11761 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11762 * to the Reader when its load method is called.
11764 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11766 Roo.data.MemoryProxy = function(data){
11770 Roo.data.MemoryProxy.superclass.constructor.call(this);
11774 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11777 * Load data from the requested source (in this case an in-memory
11778 * data object passed to the constructor), read the data object into
11779 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11780 * process that block using the passed callback.
11781 * @param {Object} params This parameter is not used by the MemoryProxy class.
11782 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11783 * object into a block of Roo.data.Records.
11784 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11785 * The function must be passed <ul>
11786 * <li>The Record block object</li>
11787 * <li>The "arg" argument from the load function</li>
11788 * <li>A boolean success indicator</li>
11790 * @param {Object} scope The scope in which to call the callback
11791 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11793 load : function(params, reader, callback, scope, arg){
11794 params = params || {};
11797 result = reader.readRecords(this.data);
11799 this.fireEvent("loadexception", this, arg, null, e);
11800 callback.call(scope, null, arg, false);
11803 callback.call(scope, result, arg, true);
11807 update : function(params, records){
11812 * Ext JS Library 1.1.1
11813 * Copyright(c) 2006-2007, Ext JS, LLC.
11815 * Originally Released Under LGPL - original licence link has changed is not relivant.
11818 * <script type="text/javascript">
11821 * @class Roo.data.HttpProxy
11822 * @extends Roo.data.DataProxy
11823 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11824 * configured to reference a certain URL.<br><br>
11826 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11827 * from which the running page was served.<br><br>
11829 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11831 * Be aware that to enable the browser to parse an XML document, the server must set
11832 * the Content-Type header in the HTTP response to "text/xml".
11834 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11835 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11836 * will be used to make the request.
11838 Roo.data.HttpProxy = function(conn){
11839 Roo.data.HttpProxy.superclass.constructor.call(this);
11840 // is conn a conn config or a real conn?
11842 this.useAjax = !conn || !conn.events;
11846 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11847 // thse are take from connection...
11850 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11853 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11854 * extra parameters to each request made by this object. (defaults to undefined)
11857 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11858 * to each request made by this object. (defaults to undefined)
11861 * @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)
11864 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11867 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11873 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11877 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11878 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11879 * a finer-grained basis than the DataProxy events.
11881 getConnection : function(){
11882 return this.useAjax ? Roo.Ajax : this.conn;
11886 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11887 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11888 * process that block using the passed callback.
11889 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11890 * for the request to the remote server.
11891 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11892 * object into a block of Roo.data.Records.
11893 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11894 * The function must be passed <ul>
11895 * <li>The Record block object</li>
11896 * <li>The "arg" argument from the load function</li>
11897 * <li>A boolean success indicator</li>
11899 * @param {Object} scope The scope in which to call the callback
11900 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11902 load : function(params, reader, callback, scope, arg){
11903 if(this.fireEvent("beforeload", this, params) !== false){
11905 params : params || {},
11907 callback : callback,
11912 callback : this.loadResponse,
11916 Roo.applyIf(o, this.conn);
11917 if(this.activeRequest){
11918 Roo.Ajax.abort(this.activeRequest);
11920 this.activeRequest = Roo.Ajax.request(o);
11922 this.conn.request(o);
11925 callback.call(scope||this, null, arg, false);
11930 loadResponse : function(o, success, response){
11931 delete this.activeRequest;
11933 this.fireEvent("loadexception", this, o, response);
11934 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11939 result = o.reader.read(response);
11941 this.fireEvent("loadexception", this, o, response, e);
11942 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11946 this.fireEvent("load", this, o, o.request.arg);
11947 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11951 update : function(dataSet){
11956 updateResponse : function(dataSet){
11961 * Ext JS Library 1.1.1
11962 * Copyright(c) 2006-2007, Ext JS, LLC.
11964 * Originally Released Under LGPL - original licence link has changed is not relivant.
11967 * <script type="text/javascript">
11971 * @class Roo.data.ScriptTagProxy
11972 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11973 * other than the originating domain of the running page.<br><br>
11975 * <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
11976 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11978 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11979 * source code that is used as the source inside a <script> tag.<br><br>
11981 * In order for the browser to process the returned data, the server must wrap the data object
11982 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11983 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11984 * depending on whether the callback name was passed:
11987 boolean scriptTag = false;
11988 String cb = request.getParameter("callback");
11991 response.setContentType("text/javascript");
11993 response.setContentType("application/x-json");
11995 Writer out = response.getWriter();
11997 out.write(cb + "(");
11999 out.print(dataBlock.toJsonString());
12006 * @param {Object} config A configuration object.
12008 Roo.data.ScriptTagProxy = function(config){
12009 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12010 Roo.apply(this, config);
12011 this.head = document.getElementsByTagName("head")[0];
12014 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12016 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12018 * @cfg {String} url The URL from which to request the data object.
12021 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12025 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12026 * the server the name of the callback function set up by the load call to process the returned data object.
12027 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12028 * javascript output which calls this named function passing the data object as its only parameter.
12030 callbackParam : "callback",
12032 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12033 * name to the request.
12038 * Load data from the configured URL, read the data object into
12039 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12040 * process that block using the passed callback.
12041 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12042 * for the request to the remote server.
12043 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12044 * object into a block of Roo.data.Records.
12045 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12046 * The function must be passed <ul>
12047 * <li>The Record block object</li>
12048 * <li>The "arg" argument from the load function</li>
12049 * <li>A boolean success indicator</li>
12051 * @param {Object} scope The scope in which to call the callback
12052 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12054 load : function(params, reader, callback, scope, arg){
12055 if(this.fireEvent("beforeload", this, params) !== false){
12057 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12059 var url = this.url;
12060 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12062 url += "&_dc=" + (new Date().getTime());
12064 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12067 cb : "stcCallback"+transId,
12068 scriptId : "stcScript"+transId,
12072 callback : callback,
12078 window[trans.cb] = function(o){
12079 conn.handleResponse(o, trans);
12082 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12084 if(this.autoAbort !== false){
12088 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12090 var script = document.createElement("script");
12091 script.setAttribute("src", url);
12092 script.setAttribute("type", "text/javascript");
12093 script.setAttribute("id", trans.scriptId);
12094 this.head.appendChild(script);
12096 this.trans = trans;
12098 callback.call(scope||this, null, arg, false);
12103 isLoading : function(){
12104 return this.trans ? true : false;
12108 * Abort the current server request.
12110 abort : function(){
12111 if(this.isLoading()){
12112 this.destroyTrans(this.trans);
12117 destroyTrans : function(trans, isLoaded){
12118 this.head.removeChild(document.getElementById(trans.scriptId));
12119 clearTimeout(trans.timeoutId);
12121 window[trans.cb] = undefined;
12123 delete window[trans.cb];
12126 // if hasn't been loaded, wait for load to remove it to prevent script error
12127 window[trans.cb] = function(){
12128 window[trans.cb] = undefined;
12130 delete window[trans.cb];
12137 handleResponse : function(o, trans){
12138 this.trans = false;
12139 this.destroyTrans(trans, true);
12142 result = trans.reader.readRecords(o);
12144 this.fireEvent("loadexception", this, o, trans.arg, e);
12145 trans.callback.call(trans.scope||window, null, trans.arg, false);
12148 this.fireEvent("load", this, o, trans.arg);
12149 trans.callback.call(trans.scope||window, result, trans.arg, true);
12153 handleFailure : function(trans){
12154 this.trans = false;
12155 this.destroyTrans(trans, false);
12156 this.fireEvent("loadexception", this, null, trans.arg);
12157 trans.callback.call(trans.scope||window, null, trans.arg, false);
12161 * Ext JS Library 1.1.1
12162 * Copyright(c) 2006-2007, Ext JS, LLC.
12164 * Originally Released Under LGPL - original licence link has changed is not relivant.
12167 * <script type="text/javascript">
12171 * @class Roo.data.JsonReader
12172 * @extends Roo.data.DataReader
12173 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12174 * based on mappings in a provided Roo.data.Record constructor.
12176 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12177 * in the reply previously.
12182 var RecordDef = Roo.data.Record.create([
12183 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12184 {name: 'occupation'} // This field will use "occupation" as the mapping.
12186 var myReader = new Roo.data.JsonReader({
12187 totalProperty: "results", // The property which contains the total dataset size (optional)
12188 root: "rows", // The property which contains an Array of row objects
12189 id: "id" // The property within each row object that provides an ID for the record (optional)
12193 * This would consume a JSON file like this:
12195 { 'results': 2, 'rows': [
12196 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12197 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12200 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12201 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12202 * paged from the remote server.
12203 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12204 * @cfg {String} root name of the property which contains the Array of row objects.
12205 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12206 * @cfg {Array} fields Array of field definition objects
12208 * Create a new JsonReader
12209 * @param {Object} meta Metadata configuration options
12210 * @param {Object} recordType Either an Array of field definition objects,
12211 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12213 Roo.data.JsonReader = function(meta, recordType){
12216 // set some defaults:
12217 Roo.applyIf(meta, {
12218 totalProperty: 'total',
12219 successProperty : 'success',
12224 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12226 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12229 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12230 * Used by Store query builder to append _requestMeta to params.
12233 metaFromRemote : false,
12235 * This method is only used by a DataProxy which has retrieved data from a remote server.
12236 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12237 * @return {Object} data A data block which is used by an Roo.data.Store object as
12238 * a cache of Roo.data.Records.
12240 read : function(response){
12241 var json = response.responseText;
12243 var o = /* eval:var:o */ eval("("+json+")");
12245 throw {message: "JsonReader.read: Json object not found"};
12251 this.metaFromRemote = true;
12252 this.meta = o.metaData;
12253 this.recordType = Roo.data.Record.create(o.metaData.fields);
12254 this.onMetaChange(this.meta, this.recordType, o);
12256 return this.readRecords(o);
12259 // private function a store will implement
12260 onMetaChange : function(meta, recordType, o){
12267 simpleAccess: function(obj, subsc) {
12274 getJsonAccessor: function(){
12276 return function(expr) {
12278 return(re.test(expr))
12279 ? new Function("obj", "return obj." + expr)
12284 return Roo.emptyFn;
12289 * Create a data block containing Roo.data.Records from an XML document.
12290 * @param {Object} o An object which contains an Array of row objects in the property specified
12291 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12292 * which contains the total size of the dataset.
12293 * @return {Object} data A data block which is used by an Roo.data.Store object as
12294 * a cache of Roo.data.Records.
12296 readRecords : function(o){
12298 * After any data loads, the raw JSON data is available for further custom processing.
12302 var s = this.meta, Record = this.recordType,
12303 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12305 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12307 if(s.totalProperty) {
12308 this.getTotal = this.getJsonAccessor(s.totalProperty);
12310 if(s.successProperty) {
12311 this.getSuccess = this.getJsonAccessor(s.successProperty);
12313 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12315 var g = this.getJsonAccessor(s.id);
12316 this.getId = function(rec) {
12318 return (r === undefined || r === "") ? null : r;
12321 this.getId = function(){return null;};
12324 for(var jj = 0; jj < fl; jj++){
12326 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12327 this.ef[jj] = this.getJsonAccessor(map);
12331 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12332 if(s.totalProperty){
12333 var vt = parseInt(this.getTotal(o), 10);
12338 if(s.successProperty){
12339 var vs = this.getSuccess(o);
12340 if(vs === false || vs === 'false'){
12345 for(var i = 0; i < c; i++){
12348 var id = this.getId(n);
12349 for(var j = 0; j < fl; j++){
12351 var v = this.ef[j](n);
12353 Roo.log('missing convert for ' + f.name);
12357 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12359 var record = new Record(values, id);
12361 records[i] = record;
12367 totalRecords : totalRecords
12372 * Ext JS Library 1.1.1
12373 * Copyright(c) 2006-2007, Ext JS, LLC.
12375 * Originally Released Under LGPL - original licence link has changed is not relivant.
12378 * <script type="text/javascript">
12382 * @class Roo.data.ArrayReader
12383 * @extends Roo.data.DataReader
12384 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12385 * Each element of that Array represents a row of data fields. The
12386 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12387 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12391 var RecordDef = Roo.data.Record.create([
12392 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12393 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12395 var myReader = new Roo.data.ArrayReader({
12396 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12400 * This would consume an Array like this:
12402 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12404 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12406 * Create a new JsonReader
12407 * @param {Object} meta Metadata configuration options.
12408 * @param {Object} recordType Either an Array of field definition objects
12409 * as specified to {@link Roo.data.Record#create},
12410 * or an {@link Roo.data.Record} object
12411 * created using {@link Roo.data.Record#create}.
12413 Roo.data.ArrayReader = function(meta, recordType){
12414 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12417 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12419 * Create a data block containing Roo.data.Records from an XML document.
12420 * @param {Object} o An Array of row objects which represents the dataset.
12421 * @return {Object} data A data block which is used by an Roo.data.Store object as
12422 * a cache of Roo.data.Records.
12424 readRecords : function(o){
12425 var sid = this.meta ? this.meta.id : null;
12426 var recordType = this.recordType, fields = recordType.prototype.fields;
12429 for(var i = 0; i < root.length; i++){
12432 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12433 for(var j = 0, jlen = fields.length; j < jlen; j++){
12434 var f = fields.items[j];
12435 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12436 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12438 values[f.name] = v;
12440 var record = new recordType(values, id);
12442 records[records.length] = record;
12446 totalRecords : records.length
12455 * @class Roo.bootstrap.ComboBox
12456 * @extends Roo.bootstrap.TriggerField
12457 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12458 * @cfg {Boolean} append (true|false) default false
12459 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12460 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12461 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12462 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12463 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12464 * @cfg {Boolean} animate default true
12465 * @cfg {Boolean} emptyResultText only for touch device
12466 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12467 * @cfg {String} emptyTitle default ''
12469 * Create a new ComboBox.
12470 * @param {Object} config Configuration options
12472 Roo.bootstrap.ComboBox = function(config){
12473 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12477 * Fires when the dropdown list is expanded
12478 * @param {Roo.bootstrap.ComboBox} combo This combo box
12483 * Fires when the dropdown list is collapsed
12484 * @param {Roo.bootstrap.ComboBox} combo This combo box
12488 * @event beforeselect
12489 * Fires before a list item is selected. Return false to cancel the selection.
12490 * @param {Roo.bootstrap.ComboBox} combo This combo box
12491 * @param {Roo.data.Record} record The data record returned from the underlying store
12492 * @param {Number} index The index of the selected item in the dropdown list
12494 'beforeselect' : true,
12497 * Fires when a list item is selected
12498 * @param {Roo.bootstrap.ComboBox} combo This combo box
12499 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12500 * @param {Number} index The index of the selected item in the dropdown list
12504 * @event beforequery
12505 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12506 * The event object passed has these properties:
12507 * @param {Roo.bootstrap.ComboBox} combo This combo box
12508 * @param {String} query The query
12509 * @param {Boolean} forceAll true to force "all" query
12510 * @param {Boolean} cancel true to cancel the query
12511 * @param {Object} e The query event object
12513 'beforequery': true,
12516 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12517 * @param {Roo.bootstrap.ComboBox} combo This combo box
12522 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12523 * @param {Roo.bootstrap.ComboBox} combo This combo box
12524 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12529 * Fires when the remove value from the combobox array
12530 * @param {Roo.bootstrap.ComboBox} combo This combo box
12534 * @event afterremove
12535 * Fires when the remove value from the combobox array
12536 * @param {Roo.bootstrap.ComboBox} combo This combo box
12538 'afterremove' : true,
12540 * @event specialfilter
12541 * Fires when specialfilter
12542 * @param {Roo.bootstrap.ComboBox} combo This combo box
12544 'specialfilter' : true,
12547 * Fires when tick the element
12548 * @param {Roo.bootstrap.ComboBox} combo This combo box
12552 * @event touchviewdisplay
12553 * Fires when touch view require special display (default is using displayField)
12554 * @param {Roo.bootstrap.ComboBox} combo This combo box
12555 * @param {Object} cfg set html .
12557 'touchviewdisplay' : true
12562 this.tickItems = [];
12564 this.selectedIndex = -1;
12565 if(this.mode == 'local'){
12566 if(config.queryDelay === undefined){
12567 this.queryDelay = 10;
12569 if(config.minChars === undefined){
12575 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12578 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12579 * rendering into an Roo.Editor, defaults to false)
12582 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12583 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12586 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12589 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12590 * the dropdown list (defaults to undefined, with no header element)
12594 * @cfg {String/Roo.Template} tpl The template to use to render the output
12598 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12600 listWidth: undefined,
12602 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12603 * mode = 'remote' or 'text' if mode = 'local')
12605 displayField: undefined,
12608 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12609 * mode = 'remote' or 'value' if mode = 'local').
12610 * Note: use of a valueField requires the user make a selection
12611 * in order for a value to be mapped.
12613 valueField: undefined,
12615 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12620 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12621 * field's data value (defaults to the underlying DOM element's name)
12623 hiddenName: undefined,
12625 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12629 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12631 selectedClass: 'active',
12634 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12638 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12639 * anchor positions (defaults to 'tl-bl')
12641 listAlign: 'tl-bl?',
12643 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12647 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12648 * query specified by the allQuery config option (defaults to 'query')
12650 triggerAction: 'query',
12652 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12653 * (defaults to 4, does not apply if editable = false)
12657 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12658 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12662 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12663 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12667 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12668 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12672 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12673 * when editable = true (defaults to false)
12675 selectOnFocus:false,
12677 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12679 queryParam: 'query',
12681 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12682 * when mode = 'remote' (defaults to 'Loading...')
12684 loadingText: 'Loading...',
12686 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12690 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12694 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12695 * traditional select (defaults to true)
12699 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12703 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12707 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12708 * listWidth has a higher value)
12712 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12713 * allow the user to set arbitrary text into the field (defaults to false)
12715 forceSelection:false,
12717 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12718 * if typeAhead = true (defaults to 250)
12720 typeAheadDelay : 250,
12722 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12723 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12725 valueNotFoundText : undefined,
12727 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12729 blockFocus : false,
12732 * @cfg {Boolean} disableClear Disable showing of clear button.
12734 disableClear : false,
12736 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12738 alwaysQuery : false,
12741 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12746 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12748 invalidClass : "has-warning",
12751 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12753 validClass : "has-success",
12756 * @cfg {Boolean} specialFilter (true|false) special filter default false
12758 specialFilter : false,
12761 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12763 mobileTouchView : true,
12766 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12768 useNativeIOS : false,
12770 ios_options : false,
12782 btnPosition : 'right',
12783 triggerList : true,
12784 showToggleBtn : true,
12786 emptyResultText: 'Empty',
12787 triggerText : 'Select',
12790 // element that contains real text value.. (when hidden is used..)
12792 getAutoCreate : function()
12797 * Render classic select for iso
12800 if(Roo.isIOS && this.useNativeIOS){
12801 cfg = this.getAutoCreateNativeIOS();
12809 if(Roo.isTouch && this.mobileTouchView){
12810 cfg = this.getAutoCreateTouchView();
12817 if(!this.tickable){
12818 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12823 * ComboBox with tickable selections
12826 var align = this.labelAlign || this.parentLabelAlign();
12829 cls : 'form-group roo-combobox-tickable' //input-group
12832 var btn_text_select = '';
12833 var btn_text_done = '';
12834 var btn_text_cancel = '';
12836 if (this.btn_text_show) {
12837 btn_text_select = 'Select';
12838 btn_text_done = 'Done';
12839 btn_text_cancel = 'Cancel';
12844 cls : 'tickable-buttons',
12849 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12850 //html : this.triggerText
12851 html: btn_text_select
12857 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12859 html: btn_text_done
12865 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12867 html: btn_text_cancel
12873 buttons.cn.unshift({
12875 cls: 'roo-select2-search-field-input'
12881 Roo.each(buttons.cn, function(c){
12883 c.cls += ' btn-' + _this.size;
12886 if (_this.disabled) {
12897 cls: 'form-hidden-field'
12901 cls: 'roo-select2-choices',
12905 cls: 'roo-select2-search-field',
12916 cls: 'roo-select2-container input-group roo-select2-container-multi',
12921 // cls: 'typeahead typeahead-long dropdown-menu',
12922 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12927 if(this.hasFeedback && !this.allowBlank){
12931 cls: 'glyphicon form-control-feedback'
12934 combobox.cn.push(feedback);
12938 if (align ==='left' && this.fieldLabel.length) {
12940 cfg.cls += ' roo-form-group-label-left';
12945 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12946 tooltip : 'This field is required'
12951 cls : 'control-label',
12952 html : this.fieldLabel
12964 var labelCfg = cfg.cn[1];
12965 var contentCfg = cfg.cn[2];
12968 if(this.indicatorpos == 'right'){
12974 cls : 'control-label',
12978 html : this.fieldLabel
12982 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12983 tooltip : 'This field is required'
12998 labelCfg = cfg.cn[0];
12999 contentCfg = cfg.cn[1];
13003 if(this.labelWidth > 12){
13004 labelCfg.style = "width: " + this.labelWidth + 'px';
13007 if(this.labelWidth < 13 && this.labelmd == 0){
13008 this.labelmd = this.labelWidth;
13011 if(this.labellg > 0){
13012 labelCfg.cls += ' col-lg-' + this.labellg;
13013 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13016 if(this.labelmd > 0){
13017 labelCfg.cls += ' col-md-' + this.labelmd;
13018 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13021 if(this.labelsm > 0){
13022 labelCfg.cls += ' col-sm-' + this.labelsm;
13023 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13026 if(this.labelxs > 0){
13027 labelCfg.cls += ' col-xs-' + this.labelxs;
13028 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13032 } else if ( this.fieldLabel.length) {
13033 // Roo.log(" label");
13037 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13038 tooltip : 'This field is required'
13042 //cls : 'input-group-addon',
13043 html : this.fieldLabel
13048 if(this.indicatorpos == 'right'){
13052 //cls : 'input-group-addon',
13053 html : this.fieldLabel
13057 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13058 tooltip : 'This field is required'
13067 // Roo.log(" no label && no align");
13074 ['xs','sm','md','lg'].map(function(size){
13075 if (settings[size]) {
13076 cfg.cls += ' col-' + size + '-' + settings[size];
13084 _initEventsCalled : false,
13087 initEvents: function()
13089 if (this._initEventsCalled) { // as we call render... prevent looping...
13092 this._initEventsCalled = true;
13095 throw "can not find store for combo";
13098 this.indicator = this.indicatorEl();
13100 this.store = Roo.factory(this.store, Roo.data);
13101 this.store.parent = this;
13103 // if we are building from html. then this element is so complex, that we can not really
13104 // use the rendered HTML.
13105 // so we have to trash and replace the previous code.
13106 if (Roo.XComponent.build_from_html) {
13107 // remove this element....
13108 var e = this.el.dom, k=0;
13109 while (e ) { e = e.previousSibling; ++k;}
13114 this.rendered = false;
13116 this.render(this.parent().getChildContainer(true), k);
13119 if(Roo.isIOS && this.useNativeIOS){
13120 this.initIOSView();
13128 if(Roo.isTouch && this.mobileTouchView){
13129 this.initTouchView();
13134 this.initTickableEvents();
13138 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13140 if(this.hiddenName){
13142 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13144 this.hiddenField.dom.value =
13145 this.hiddenValue !== undefined ? this.hiddenValue :
13146 this.value !== undefined ? this.value : '';
13148 // prevent input submission
13149 this.el.dom.removeAttribute('name');
13150 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13155 // this.el.dom.setAttribute('autocomplete', 'off');
13158 var cls = 'x-combo-list';
13160 //this.list = new Roo.Layer({
13161 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13167 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13168 _this.list.setWidth(lw);
13171 this.list.on('mouseover', this.onViewOver, this);
13172 this.list.on('mousemove', this.onViewMove, this);
13173 this.list.on('scroll', this.onViewScroll, this);
13176 this.list.swallowEvent('mousewheel');
13177 this.assetHeight = 0;
13180 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13181 this.assetHeight += this.header.getHeight();
13184 this.innerList = this.list.createChild({cls:cls+'-inner'});
13185 this.innerList.on('mouseover', this.onViewOver, this);
13186 this.innerList.on('mousemove', this.onViewMove, this);
13187 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13189 if(this.allowBlank && !this.pageSize && !this.disableClear){
13190 this.footer = this.list.createChild({cls:cls+'-ft'});
13191 this.pageTb = new Roo.Toolbar(this.footer);
13195 this.footer = this.list.createChild({cls:cls+'-ft'});
13196 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13197 {pageSize: this.pageSize});
13201 if (this.pageTb && this.allowBlank && !this.disableClear) {
13203 this.pageTb.add(new Roo.Toolbar.Fill(), {
13204 cls: 'x-btn-icon x-btn-clear',
13206 handler: function()
13209 _this.clearValue();
13210 _this.onSelect(false, -1);
13215 this.assetHeight += this.footer.getHeight();
13220 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13223 this.view = new Roo.View(this.list, this.tpl, {
13224 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13226 //this.view.wrapEl.setDisplayed(false);
13227 this.view.on('click', this.onViewClick, this);
13230 this.store.on('beforeload', this.onBeforeLoad, this);
13231 this.store.on('load', this.onLoad, this);
13232 this.store.on('loadexception', this.onLoadException, this);
13234 if(this.resizable){
13235 this.resizer = new Roo.Resizable(this.list, {
13236 pinned:true, handles:'se'
13238 this.resizer.on('resize', function(r, w, h){
13239 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13240 this.listWidth = w;
13241 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13242 this.restrictHeight();
13244 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13247 if(!this.editable){
13248 this.editable = true;
13249 this.setEditable(false);
13254 if (typeof(this.events.add.listeners) != 'undefined') {
13256 this.addicon = this.wrap.createChild(
13257 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13259 this.addicon.on('click', function(e) {
13260 this.fireEvent('add', this);
13263 if (typeof(this.events.edit.listeners) != 'undefined') {
13265 this.editicon = this.wrap.createChild(
13266 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13267 if (this.addicon) {
13268 this.editicon.setStyle('margin-left', '40px');
13270 this.editicon.on('click', function(e) {
13272 // we fire even if inothing is selected..
13273 this.fireEvent('edit', this, this.lastData );
13279 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13280 "up" : function(e){
13281 this.inKeyMode = true;
13285 "down" : function(e){
13286 if(!this.isExpanded()){
13287 this.onTriggerClick();
13289 this.inKeyMode = true;
13294 "enter" : function(e){
13295 // this.onViewClick();
13299 if(this.fireEvent("specialkey", this, e)){
13300 this.onViewClick(false);
13306 "esc" : function(e){
13310 "tab" : function(e){
13313 if(this.fireEvent("specialkey", this, e)){
13314 this.onViewClick(false);
13322 doRelay : function(foo, bar, hname){
13323 if(hname == 'down' || this.scope.isExpanded()){
13324 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13333 this.queryDelay = Math.max(this.queryDelay || 10,
13334 this.mode == 'local' ? 10 : 250);
13337 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13339 if(this.typeAhead){
13340 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13342 if(this.editable !== false){
13343 this.inputEl().on("keyup", this.onKeyUp, this);
13345 if(this.forceSelection){
13346 this.inputEl().on('blur', this.doForce, this);
13350 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13351 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13355 initTickableEvents: function()
13359 if(this.hiddenName){
13361 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13363 this.hiddenField.dom.value =
13364 this.hiddenValue !== undefined ? this.hiddenValue :
13365 this.value !== undefined ? this.value : '';
13367 // prevent input submission
13368 this.el.dom.removeAttribute('name');
13369 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13374 // this.list = this.el.select('ul.dropdown-menu',true).first();
13376 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13377 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13378 if(this.triggerList){
13379 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13382 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13383 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13385 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13386 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13388 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13389 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13391 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13392 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13393 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13396 this.cancelBtn.hide();
13401 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13402 _this.list.setWidth(lw);
13405 this.list.on('mouseover', this.onViewOver, this);
13406 this.list.on('mousemove', this.onViewMove, this);
13408 this.list.on('scroll', this.onViewScroll, this);
13411 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13414 this.view = new Roo.View(this.list, this.tpl, {
13415 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13418 //this.view.wrapEl.setDisplayed(false);
13419 this.view.on('click', this.onViewClick, this);
13423 this.store.on('beforeload', this.onBeforeLoad, this);
13424 this.store.on('load', this.onLoad, this);
13425 this.store.on('loadexception', this.onLoadException, this);
13428 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13429 "up" : function(e){
13430 this.inKeyMode = true;
13434 "down" : function(e){
13435 this.inKeyMode = true;
13439 "enter" : function(e){
13440 if(this.fireEvent("specialkey", this, e)){
13441 this.onViewClick(false);
13447 "esc" : function(e){
13448 this.onTickableFooterButtonClick(e, false, false);
13451 "tab" : function(e){
13452 this.fireEvent("specialkey", this, e);
13454 this.onTickableFooterButtonClick(e, false, false);
13461 doRelay : function(e, fn, key){
13462 if(this.scope.isExpanded()){
13463 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13472 this.queryDelay = Math.max(this.queryDelay || 10,
13473 this.mode == 'local' ? 10 : 250);
13476 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13478 if(this.typeAhead){
13479 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13482 if(this.editable !== false){
13483 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13486 this.indicator = this.indicatorEl();
13488 if(this.indicator){
13489 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13490 this.indicator.hide();
13495 onDestroy : function(){
13497 this.view.setStore(null);
13498 this.view.el.removeAllListeners();
13499 this.view.el.remove();
13500 this.view.purgeListeners();
13503 this.list.dom.innerHTML = '';
13507 this.store.un('beforeload', this.onBeforeLoad, this);
13508 this.store.un('load', this.onLoad, this);
13509 this.store.un('loadexception', this.onLoadException, this);
13511 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13515 fireKey : function(e){
13516 if(e.isNavKeyPress() && !this.list.isVisible()){
13517 this.fireEvent("specialkey", this, e);
13522 onResize: function(w, h){
13523 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13525 // if(typeof w != 'number'){
13526 // // we do not handle it!?!?
13529 // var tw = this.trigger.getWidth();
13530 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13531 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13533 // this.inputEl().setWidth( this.adjustWidth('input', x));
13535 // //this.trigger.setStyle('left', x+'px');
13537 // if(this.list && this.listWidth === undefined){
13538 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13539 // this.list.setWidth(lw);
13540 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13548 * Allow or prevent the user from directly editing the field text. If false is passed,
13549 * the user will only be able to select from the items defined in the dropdown list. This method
13550 * is the runtime equivalent of setting the 'editable' config option at config time.
13551 * @param {Boolean} value True to allow the user to directly edit the field text
13553 setEditable : function(value){
13554 if(value == this.editable){
13557 this.editable = value;
13559 this.inputEl().dom.setAttribute('readOnly', true);
13560 this.inputEl().on('mousedown', this.onTriggerClick, this);
13561 this.inputEl().addClass('x-combo-noedit');
13563 this.inputEl().dom.setAttribute('readOnly', false);
13564 this.inputEl().un('mousedown', this.onTriggerClick, this);
13565 this.inputEl().removeClass('x-combo-noedit');
13571 onBeforeLoad : function(combo,opts){
13572 if(!this.hasFocus){
13576 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13578 this.restrictHeight();
13579 this.selectedIndex = -1;
13583 onLoad : function(){
13585 this.hasQuery = false;
13587 if(!this.hasFocus){
13591 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13592 this.loading.hide();
13595 if(this.store.getCount() > 0){
13598 this.restrictHeight();
13599 if(this.lastQuery == this.allQuery){
13600 if(this.editable && !this.tickable){
13601 this.inputEl().dom.select();
13605 !this.selectByValue(this.value, true) &&
13608 !this.store.lastOptions ||
13609 typeof(this.store.lastOptions.add) == 'undefined' ||
13610 this.store.lastOptions.add != true
13613 this.select(0, true);
13616 if(this.autoFocus){
13619 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13620 this.taTask.delay(this.typeAheadDelay);
13624 this.onEmptyResults();
13630 onLoadException : function()
13632 this.hasQuery = false;
13634 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13635 this.loading.hide();
13638 if(this.tickable && this.editable){
13643 // only causes errors at present
13644 //Roo.log(this.store.reader.jsonData);
13645 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13647 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13653 onTypeAhead : function(){
13654 if(this.store.getCount() > 0){
13655 var r = this.store.getAt(0);
13656 var newValue = r.data[this.displayField];
13657 var len = newValue.length;
13658 var selStart = this.getRawValue().length;
13660 if(selStart != len){
13661 this.setRawValue(newValue);
13662 this.selectText(selStart, newValue.length);
13668 onSelect : function(record, index){
13670 if(this.fireEvent('beforeselect', this, record, index) !== false){
13672 this.setFromData(index > -1 ? record.data : false);
13675 this.fireEvent('select', this, record, index);
13680 * Returns the currently selected field value or empty string if no value is set.
13681 * @return {String} value The selected value
13683 getValue : function()
13685 if(Roo.isIOS && this.useNativeIOS){
13686 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13690 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13693 if(this.valueField){
13694 return typeof this.value != 'undefined' ? this.value : '';
13696 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13700 getRawValue : function()
13702 if(Roo.isIOS && this.useNativeIOS){
13703 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13706 var v = this.inputEl().getValue();
13712 * Clears any text/value currently set in the field
13714 clearValue : function(){
13716 if(this.hiddenField){
13717 this.hiddenField.dom.value = '';
13720 this.setRawValue('');
13721 this.lastSelectionText = '';
13722 this.lastData = false;
13724 var close = this.closeTriggerEl();
13735 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13736 * will be displayed in the field. If the value does not match the data value of an existing item,
13737 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13738 * Otherwise the field will be blank (although the value will still be set).
13739 * @param {String} value The value to match
13741 setValue : function(v)
13743 if(Roo.isIOS && this.useNativeIOS){
13744 this.setIOSValue(v);
13754 if(this.valueField){
13755 var r = this.findRecord(this.valueField, v);
13757 text = r.data[this.displayField];
13758 }else if(this.valueNotFoundText !== undefined){
13759 text = this.valueNotFoundText;
13762 this.lastSelectionText = text;
13763 if(this.hiddenField){
13764 this.hiddenField.dom.value = v;
13766 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13769 var close = this.closeTriggerEl();
13772 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13778 * @property {Object} the last set data for the element
13783 * Sets the value of the field based on a object which is related to the record format for the store.
13784 * @param {Object} value the value to set as. or false on reset?
13786 setFromData : function(o){
13793 var dv = ''; // display value
13794 var vv = ''; // value value..
13796 if (this.displayField) {
13797 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13799 // this is an error condition!!!
13800 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13803 if(this.valueField){
13804 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13807 var close = this.closeTriggerEl();
13810 if(dv.length || vv * 1 > 0){
13812 this.blockFocus=true;
13818 if(this.hiddenField){
13819 this.hiddenField.dom.value = vv;
13821 this.lastSelectionText = dv;
13822 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13826 // no hidden field.. - we store the value in 'value', but still display
13827 // display field!!!!
13828 this.lastSelectionText = dv;
13829 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13836 reset : function(){
13837 // overridden so that last data is reset..
13844 this.setValue(this.originalValue);
13845 //this.clearInvalid();
13846 this.lastData = false;
13848 this.view.clearSelections();
13854 findRecord : function(prop, value){
13856 if(this.store.getCount() > 0){
13857 this.store.each(function(r){
13858 if(r.data[prop] == value){
13868 getName: function()
13870 // returns hidden if it's set..
13871 if (!this.rendered) {return ''};
13872 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13876 onViewMove : function(e, t){
13877 this.inKeyMode = false;
13881 onViewOver : function(e, t){
13882 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13885 var item = this.view.findItemFromChild(t);
13888 var index = this.view.indexOf(item);
13889 this.select(index, false);
13894 onViewClick : function(view, doFocus, el, e)
13896 var index = this.view.getSelectedIndexes()[0];
13898 var r = this.store.getAt(index);
13902 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13909 Roo.each(this.tickItems, function(v,k){
13911 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13913 _this.tickItems.splice(k, 1);
13915 if(typeof(e) == 'undefined' && view == false){
13916 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13928 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13929 this.tickItems.push(r.data);
13932 if(typeof(e) == 'undefined' && view == false){
13933 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13940 this.onSelect(r, index);
13942 if(doFocus !== false && !this.blockFocus){
13943 this.inputEl().focus();
13948 restrictHeight : function(){
13949 //this.innerList.dom.style.height = '';
13950 //var inner = this.innerList.dom;
13951 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13952 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13953 //this.list.beginUpdate();
13954 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13955 this.list.alignTo(this.inputEl(), this.listAlign);
13956 this.list.alignTo(this.inputEl(), this.listAlign);
13957 //this.list.endUpdate();
13961 onEmptyResults : function(){
13963 if(this.tickable && this.editable){
13964 this.restrictHeight();
13972 * Returns true if the dropdown list is expanded, else false.
13974 isExpanded : function(){
13975 return this.list.isVisible();
13979 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13980 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13981 * @param {String} value The data value of the item to select
13982 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13983 * selected item if it is not currently in view (defaults to true)
13984 * @return {Boolean} True if the value matched an item in the list, else false
13986 selectByValue : function(v, scrollIntoView){
13987 if(v !== undefined && v !== null){
13988 var r = this.findRecord(this.valueField || this.displayField, v);
13990 this.select(this.store.indexOf(r), scrollIntoView);
13998 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13999 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14000 * @param {Number} index The zero-based index of the list item to select
14001 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14002 * selected item if it is not currently in view (defaults to true)
14004 select : function(index, scrollIntoView){
14005 this.selectedIndex = index;
14006 this.view.select(index);
14007 if(scrollIntoView !== false){
14008 var el = this.view.getNode(index);
14010 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14013 this.list.scrollChildIntoView(el, false);
14019 selectNext : function(){
14020 var ct = this.store.getCount();
14022 if(this.selectedIndex == -1){
14024 }else if(this.selectedIndex < ct-1){
14025 this.select(this.selectedIndex+1);
14031 selectPrev : function(){
14032 var ct = this.store.getCount();
14034 if(this.selectedIndex == -1){
14036 }else if(this.selectedIndex != 0){
14037 this.select(this.selectedIndex-1);
14043 onKeyUp : function(e){
14044 if(this.editable !== false && !e.isSpecialKey()){
14045 this.lastKey = e.getKey();
14046 this.dqTask.delay(this.queryDelay);
14051 validateBlur : function(){
14052 return !this.list || !this.list.isVisible();
14056 initQuery : function(){
14058 var v = this.getRawValue();
14060 if(this.tickable && this.editable){
14061 v = this.tickableInputEl().getValue();
14068 doForce : function(){
14069 if(this.inputEl().dom.value.length > 0){
14070 this.inputEl().dom.value =
14071 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14077 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14078 * query allowing the query action to be canceled if needed.
14079 * @param {String} query The SQL query to execute
14080 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14081 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14082 * saved in the current store (defaults to false)
14084 doQuery : function(q, forceAll){
14086 if(q === undefined || q === null){
14091 forceAll: forceAll,
14095 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14100 forceAll = qe.forceAll;
14101 if(forceAll === true || (q.length >= this.minChars)){
14103 this.hasQuery = true;
14105 if(this.lastQuery != q || this.alwaysQuery){
14106 this.lastQuery = q;
14107 if(this.mode == 'local'){
14108 this.selectedIndex = -1;
14110 this.store.clearFilter();
14113 if(this.specialFilter){
14114 this.fireEvent('specialfilter', this);
14119 this.store.filter(this.displayField, q);
14122 this.store.fireEvent("datachanged", this.store);
14129 this.store.baseParams[this.queryParam] = q;
14131 var options = {params : this.getParams(q)};
14134 options.add = true;
14135 options.params.start = this.page * this.pageSize;
14138 this.store.load(options);
14141 * this code will make the page width larger, at the beginning, the list not align correctly,
14142 * we should expand the list on onLoad
14143 * so command out it
14148 this.selectedIndex = -1;
14153 this.loadNext = false;
14157 getParams : function(q){
14159 //p[this.queryParam] = q;
14163 p.limit = this.pageSize;
14169 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14171 collapse : function(){
14172 if(!this.isExpanded()){
14178 this.hasFocus = false;
14182 this.cancelBtn.hide();
14183 this.trigger.show();
14186 this.tickableInputEl().dom.value = '';
14187 this.tickableInputEl().blur();
14192 Roo.get(document).un('mousedown', this.collapseIf, this);
14193 Roo.get(document).un('mousewheel', this.collapseIf, this);
14194 if (!this.editable) {
14195 Roo.get(document).un('keydown', this.listKeyPress, this);
14197 this.fireEvent('collapse', this);
14203 collapseIf : function(e){
14204 var in_combo = e.within(this.el);
14205 var in_list = e.within(this.list);
14206 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14208 if (in_combo || in_list || is_list) {
14209 //e.stopPropagation();
14214 this.onTickableFooterButtonClick(e, false, false);
14222 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14224 expand : function(){
14226 if(this.isExpanded() || !this.hasFocus){
14230 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14231 this.list.setWidth(lw);
14237 this.restrictHeight();
14241 this.tickItems = Roo.apply([], this.item);
14244 this.cancelBtn.show();
14245 this.trigger.hide();
14248 this.tickableInputEl().focus();
14253 Roo.get(document).on('mousedown', this.collapseIf, this);
14254 Roo.get(document).on('mousewheel', this.collapseIf, this);
14255 if (!this.editable) {
14256 Roo.get(document).on('keydown', this.listKeyPress, this);
14259 this.fireEvent('expand', this);
14263 // Implements the default empty TriggerField.onTriggerClick function
14264 onTriggerClick : function(e)
14266 Roo.log('trigger click');
14268 if(this.disabled || !this.triggerList){
14273 this.loadNext = false;
14275 if(this.isExpanded()){
14277 if (!this.blockFocus) {
14278 this.inputEl().focus();
14282 this.hasFocus = true;
14283 if(this.triggerAction == 'all') {
14284 this.doQuery(this.allQuery, true);
14286 this.doQuery(this.getRawValue());
14288 if (!this.blockFocus) {
14289 this.inputEl().focus();
14294 onTickableTriggerClick : function(e)
14301 this.loadNext = false;
14302 this.hasFocus = true;
14304 if(this.triggerAction == 'all') {
14305 this.doQuery(this.allQuery, true);
14307 this.doQuery(this.getRawValue());
14311 onSearchFieldClick : function(e)
14313 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14314 this.onTickableFooterButtonClick(e, false, false);
14318 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14323 this.loadNext = false;
14324 this.hasFocus = true;
14326 if(this.triggerAction == 'all') {
14327 this.doQuery(this.allQuery, true);
14329 this.doQuery(this.getRawValue());
14333 listKeyPress : function(e)
14335 //Roo.log('listkeypress');
14336 // scroll to first matching element based on key pres..
14337 if (e.isSpecialKey()) {
14340 var k = String.fromCharCode(e.getKey()).toUpperCase();
14343 var csel = this.view.getSelectedNodes();
14344 var cselitem = false;
14346 var ix = this.view.indexOf(csel[0]);
14347 cselitem = this.store.getAt(ix);
14348 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14354 this.store.each(function(v) {
14356 // start at existing selection.
14357 if (cselitem.id == v.id) {
14363 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14364 match = this.store.indexOf(v);
14370 if (match === false) {
14371 return true; // no more action?
14374 this.view.select(match);
14375 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14376 sn.scrollIntoView(sn.dom.parentNode, false);
14379 onViewScroll : function(e, t){
14381 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){
14385 this.hasQuery = true;
14387 this.loading = this.list.select('.loading', true).first();
14389 if(this.loading === null){
14390 this.list.createChild({
14392 cls: 'loading roo-select2-more-results roo-select2-active',
14393 html: 'Loading more results...'
14396 this.loading = this.list.select('.loading', true).first();
14398 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14400 this.loading.hide();
14403 this.loading.show();
14408 this.loadNext = true;
14410 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14415 addItem : function(o)
14417 var dv = ''; // display value
14419 if (this.displayField) {
14420 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14422 // this is an error condition!!!
14423 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14430 var choice = this.choices.createChild({
14432 cls: 'roo-select2-search-choice',
14441 cls: 'roo-select2-search-choice-close fa fa-times',
14446 }, this.searchField);
14448 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14450 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14458 this.inputEl().dom.value = '';
14463 onRemoveItem : function(e, _self, o)
14465 e.preventDefault();
14467 this.lastItem = Roo.apply([], this.item);
14469 var index = this.item.indexOf(o.data) * 1;
14472 Roo.log('not this item?!');
14476 this.item.splice(index, 1);
14481 this.fireEvent('remove', this, e);
14487 syncValue : function()
14489 if(!this.item.length){
14496 Roo.each(this.item, function(i){
14497 if(_this.valueField){
14498 value.push(i[_this.valueField]);
14505 this.value = value.join(',');
14507 if(this.hiddenField){
14508 this.hiddenField.dom.value = this.value;
14511 this.store.fireEvent("datachanged", this.store);
14516 clearItem : function()
14518 if(!this.multiple){
14524 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14532 if(this.tickable && !Roo.isTouch){
14533 this.view.refresh();
14537 inputEl: function ()
14539 if(Roo.isIOS && this.useNativeIOS){
14540 return this.el.select('select.roo-ios-select', true).first();
14543 if(Roo.isTouch && this.mobileTouchView){
14544 return this.el.select('input.form-control',true).first();
14548 return this.searchField;
14551 return this.el.select('input.form-control',true).first();
14554 onTickableFooterButtonClick : function(e, btn, el)
14556 e.preventDefault();
14558 this.lastItem = Roo.apply([], this.item);
14560 if(btn && btn.name == 'cancel'){
14561 this.tickItems = Roo.apply([], this.item);
14570 Roo.each(this.tickItems, function(o){
14578 validate : function()
14580 var v = this.getRawValue();
14583 v = this.getValue();
14586 if(this.disabled || this.allowBlank || v.length){
14591 this.markInvalid();
14595 tickableInputEl : function()
14597 if(!this.tickable || !this.editable){
14598 return this.inputEl();
14601 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14605 getAutoCreateTouchView : function()
14610 cls: 'form-group' //input-group
14616 type : this.inputType,
14617 cls : 'form-control x-combo-noedit',
14618 autocomplete: 'new-password',
14619 placeholder : this.placeholder || '',
14624 input.name = this.name;
14628 input.cls += ' input-' + this.size;
14631 if (this.disabled) {
14632 input.disabled = true;
14643 inputblock.cls += ' input-group';
14645 inputblock.cn.unshift({
14647 cls : 'input-group-addon',
14652 if(this.removable && !this.multiple){
14653 inputblock.cls += ' roo-removable';
14655 inputblock.cn.push({
14658 cls : 'roo-combo-removable-btn close'
14662 if(this.hasFeedback && !this.allowBlank){
14664 inputblock.cls += ' has-feedback';
14666 inputblock.cn.push({
14668 cls: 'glyphicon form-control-feedback'
14675 inputblock.cls += (this.before) ? '' : ' input-group';
14677 inputblock.cn.push({
14679 cls : 'input-group-addon',
14690 cls: 'form-hidden-field'
14704 cls: 'form-hidden-field'
14708 cls: 'roo-select2-choices',
14712 cls: 'roo-select2-search-field',
14725 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14731 if(!this.multiple && this.showToggleBtn){
14738 if (this.caret != false) {
14741 cls: 'fa fa-' + this.caret
14748 cls : 'input-group-addon btn dropdown-toggle',
14753 cls: 'combobox-clear',
14767 combobox.cls += ' roo-select2-container-multi';
14770 var align = this.labelAlign || this.parentLabelAlign();
14772 if (align ==='left' && this.fieldLabel.length) {
14777 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14778 tooltip : 'This field is required'
14782 cls : 'control-label',
14783 html : this.fieldLabel
14794 var labelCfg = cfg.cn[1];
14795 var contentCfg = cfg.cn[2];
14798 if(this.indicatorpos == 'right'){
14803 cls : 'control-label',
14807 html : this.fieldLabel
14811 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14812 tooltip : 'This field is required'
14825 labelCfg = cfg.cn[0];
14826 contentCfg = cfg.cn[1];
14831 if(this.labelWidth > 12){
14832 labelCfg.style = "width: " + this.labelWidth + 'px';
14835 if(this.labelWidth < 13 && this.labelmd == 0){
14836 this.labelmd = this.labelWidth;
14839 if(this.labellg > 0){
14840 labelCfg.cls += ' col-lg-' + this.labellg;
14841 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14844 if(this.labelmd > 0){
14845 labelCfg.cls += ' col-md-' + this.labelmd;
14846 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14849 if(this.labelsm > 0){
14850 labelCfg.cls += ' col-sm-' + this.labelsm;
14851 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14854 if(this.labelxs > 0){
14855 labelCfg.cls += ' col-xs-' + this.labelxs;
14856 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14860 } else if ( this.fieldLabel.length) {
14864 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14865 tooltip : 'This field is required'
14869 cls : 'control-label',
14870 html : this.fieldLabel
14881 if(this.indicatorpos == 'right'){
14885 cls : 'control-label',
14886 html : this.fieldLabel,
14890 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14891 tooltip : 'This field is required'
14908 var settings = this;
14910 ['xs','sm','md','lg'].map(function(size){
14911 if (settings[size]) {
14912 cfg.cls += ' col-' + size + '-' + settings[size];
14919 initTouchView : function()
14921 this.renderTouchView();
14923 this.touchViewEl.on('scroll', function(){
14924 this.el.dom.scrollTop = 0;
14927 this.originalValue = this.getValue();
14929 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14931 this.inputEl().on("click", this.showTouchView, this);
14932 if (this.triggerEl) {
14933 this.triggerEl.on("click", this.showTouchView, this);
14937 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14938 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14940 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14942 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14943 this.store.on('load', this.onTouchViewLoad, this);
14944 this.store.on('loadexception', this.onTouchViewLoadException, this);
14946 if(this.hiddenName){
14948 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14950 this.hiddenField.dom.value =
14951 this.hiddenValue !== undefined ? this.hiddenValue :
14952 this.value !== undefined ? this.value : '';
14954 this.el.dom.removeAttribute('name');
14955 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14959 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14960 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14963 if(this.removable && !this.multiple){
14964 var close = this.closeTriggerEl();
14966 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14967 close.on('click', this.removeBtnClick, this, close);
14971 * fix the bug in Safari iOS8
14973 this.inputEl().on("focus", function(e){
14974 document.activeElement.blur();
14982 renderTouchView : function()
14984 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14985 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14987 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14988 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14990 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14991 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14992 this.touchViewBodyEl.setStyle('overflow', 'auto');
14994 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14995 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14997 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14998 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15002 showTouchView : function()
15008 this.touchViewHeaderEl.hide();
15010 if(this.modalTitle.length){
15011 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15012 this.touchViewHeaderEl.show();
15015 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15016 this.touchViewEl.show();
15018 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15020 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15021 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15023 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15025 if(this.modalTitle.length){
15026 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15029 this.touchViewBodyEl.setHeight(bodyHeight);
15033 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15035 this.touchViewEl.addClass('in');
15038 this.doTouchViewQuery();
15042 hideTouchView : function()
15044 this.touchViewEl.removeClass('in');
15048 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15050 this.touchViewEl.setStyle('display', 'none');
15055 setTouchViewValue : function()
15062 Roo.each(this.tickItems, function(o){
15067 this.hideTouchView();
15070 doTouchViewQuery : function()
15079 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15083 if(!this.alwaysQuery || this.mode == 'local'){
15084 this.onTouchViewLoad();
15091 onTouchViewBeforeLoad : function(combo,opts)
15097 onTouchViewLoad : function()
15099 if(this.store.getCount() < 1){
15100 this.onTouchViewEmptyResults();
15104 this.clearTouchView();
15106 var rawValue = this.getRawValue();
15108 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15110 this.tickItems = [];
15112 this.store.data.each(function(d, rowIndex){
15113 var row = this.touchViewListGroup.createChild(template);
15115 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15116 row.addClass(d.data.cls);
15119 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15122 html : d.data[this.displayField]
15125 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15126 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15129 row.removeClass('selected');
15130 if(!this.multiple && this.valueField &&
15131 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15134 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15135 row.addClass('selected');
15138 if(this.multiple && this.valueField &&
15139 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15143 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15144 this.tickItems.push(d.data);
15147 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15151 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15153 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15155 if(this.modalTitle.length){
15156 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15159 var listHeight = this.touchViewListGroup.getHeight();
15163 if(firstChecked && listHeight > bodyHeight){
15164 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15169 onTouchViewLoadException : function()
15171 this.hideTouchView();
15174 onTouchViewEmptyResults : function()
15176 this.clearTouchView();
15178 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15180 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15184 clearTouchView : function()
15186 this.touchViewListGroup.dom.innerHTML = '';
15189 onTouchViewClick : function(e, el, o)
15191 e.preventDefault();
15194 var rowIndex = o.rowIndex;
15196 var r = this.store.getAt(rowIndex);
15198 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15200 if(!this.multiple){
15201 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15202 c.dom.removeAttribute('checked');
15205 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15207 this.setFromData(r.data);
15209 var close = this.closeTriggerEl();
15215 this.hideTouchView();
15217 this.fireEvent('select', this, r, rowIndex);
15222 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15223 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15224 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15228 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15229 this.addItem(r.data);
15230 this.tickItems.push(r.data);
15234 getAutoCreateNativeIOS : function()
15237 cls: 'form-group' //input-group,
15242 cls : 'roo-ios-select'
15246 combobox.name = this.name;
15249 if (this.disabled) {
15250 combobox.disabled = true;
15253 var settings = this;
15255 ['xs','sm','md','lg'].map(function(size){
15256 if (settings[size]) {
15257 cfg.cls += ' col-' + size + '-' + settings[size];
15267 initIOSView : function()
15269 this.store.on('load', this.onIOSViewLoad, this);
15274 onIOSViewLoad : function()
15276 if(this.store.getCount() < 1){
15280 this.clearIOSView();
15282 if(this.allowBlank) {
15284 var default_text = '-- SELECT --';
15286 if(this.placeholder.length){
15287 default_text = this.placeholder;
15290 if(this.emptyTitle.length){
15291 default_text += ' - ' + this.emptyTitle + ' -';
15294 var opt = this.inputEl().createChild({
15297 html : default_text
15301 o[this.valueField] = 0;
15302 o[this.displayField] = default_text;
15304 this.ios_options.push({
15311 this.store.data.each(function(d, rowIndex){
15315 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15316 html = d.data[this.displayField];
15321 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15322 value = d.data[this.valueField];
15331 if(this.value == d.data[this.valueField]){
15332 option['selected'] = true;
15335 var opt = this.inputEl().createChild(option);
15337 this.ios_options.push({
15344 this.inputEl().on('change', function(){
15345 this.fireEvent('select', this);
15350 clearIOSView: function()
15352 this.inputEl().dom.innerHTML = '';
15354 this.ios_options = [];
15357 setIOSValue: function(v)
15361 if(!this.ios_options){
15365 Roo.each(this.ios_options, function(opts){
15367 opts.el.dom.removeAttribute('selected');
15369 if(opts.data[this.valueField] != v){
15373 opts.el.dom.setAttribute('selected', true);
15379 * @cfg {Boolean} grow
15383 * @cfg {Number} growMin
15387 * @cfg {Number} growMax
15396 Roo.apply(Roo.bootstrap.ComboBox, {
15400 cls: 'modal-header',
15422 cls: 'list-group-item',
15426 cls: 'roo-combobox-list-group-item-value'
15430 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15444 listItemCheckbox : {
15446 cls: 'list-group-item',
15450 cls: 'roo-combobox-list-group-item-value'
15454 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15470 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15475 cls: 'modal-footer',
15483 cls: 'col-xs-6 text-left',
15486 cls: 'btn btn-danger roo-touch-view-cancel',
15492 cls: 'col-xs-6 text-right',
15495 cls: 'btn btn-success roo-touch-view-ok',
15506 Roo.apply(Roo.bootstrap.ComboBox, {
15508 touchViewTemplate : {
15510 cls: 'modal fade roo-combobox-touch-view',
15514 cls: 'modal-dialog',
15515 style : 'position:fixed', // we have to fix position....
15519 cls: 'modal-content',
15521 Roo.bootstrap.ComboBox.header,
15522 Roo.bootstrap.ComboBox.body,
15523 Roo.bootstrap.ComboBox.footer
15532 * Ext JS Library 1.1.1
15533 * Copyright(c) 2006-2007, Ext JS, LLC.
15535 * Originally Released Under LGPL - original licence link has changed is not relivant.
15538 * <script type="text/javascript">
15543 * @extends Roo.util.Observable
15544 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15545 * This class also supports single and multi selection modes. <br>
15546 * Create a data model bound view:
15548 var store = new Roo.data.Store(...);
15550 var view = new Roo.View({
15552 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15554 singleSelect: true,
15555 selectedClass: "ydataview-selected",
15559 // listen for node click?
15560 view.on("click", function(vw, index, node, e){
15561 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15565 dataModel.load("foobar.xml");
15567 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15569 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15570 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15572 * Note: old style constructor is still suported (container, template, config)
15575 * Create a new View
15576 * @param {Object} config The config object
15579 Roo.View = function(config, depreciated_tpl, depreciated_config){
15581 this.parent = false;
15583 if (typeof(depreciated_tpl) == 'undefined') {
15584 // new way.. - universal constructor.
15585 Roo.apply(this, config);
15586 this.el = Roo.get(this.el);
15589 this.el = Roo.get(config);
15590 this.tpl = depreciated_tpl;
15591 Roo.apply(this, depreciated_config);
15593 this.wrapEl = this.el.wrap().wrap();
15594 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15597 if(typeof(this.tpl) == "string"){
15598 this.tpl = new Roo.Template(this.tpl);
15600 // support xtype ctors..
15601 this.tpl = new Roo.factory(this.tpl, Roo);
15605 this.tpl.compile();
15610 * @event beforeclick
15611 * Fires before a click is processed. Returns false to cancel the default action.
15612 * @param {Roo.View} this
15613 * @param {Number} index The index of the target node
15614 * @param {HTMLElement} node The target node
15615 * @param {Roo.EventObject} e The raw event object
15617 "beforeclick" : true,
15620 * Fires when a template node is clicked.
15621 * @param {Roo.View} this
15622 * @param {Number} index The index of the target node
15623 * @param {HTMLElement} node The target node
15624 * @param {Roo.EventObject} e The raw event object
15629 * Fires when a template node is double clicked.
15630 * @param {Roo.View} this
15631 * @param {Number} index The index of the target node
15632 * @param {HTMLElement} node The target node
15633 * @param {Roo.EventObject} e The raw event object
15637 * @event contextmenu
15638 * Fires when a template node is right clicked.
15639 * @param {Roo.View} this
15640 * @param {Number} index The index of the target node
15641 * @param {HTMLElement} node The target node
15642 * @param {Roo.EventObject} e The raw event object
15644 "contextmenu" : true,
15646 * @event selectionchange
15647 * Fires when the selected nodes change.
15648 * @param {Roo.View} this
15649 * @param {Array} selections Array of the selected nodes
15651 "selectionchange" : true,
15654 * @event beforeselect
15655 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15656 * @param {Roo.View} this
15657 * @param {HTMLElement} node The node to be selected
15658 * @param {Array} selections Array of currently selected nodes
15660 "beforeselect" : true,
15662 * @event preparedata
15663 * Fires on every row to render, to allow you to change the data.
15664 * @param {Roo.View} this
15665 * @param {Object} data to be rendered (change this)
15667 "preparedata" : true
15675 "click": this.onClick,
15676 "dblclick": this.onDblClick,
15677 "contextmenu": this.onContextMenu,
15681 this.selections = [];
15683 this.cmp = new Roo.CompositeElementLite([]);
15685 this.store = Roo.factory(this.store, Roo.data);
15686 this.setStore(this.store, true);
15689 if ( this.footer && this.footer.xtype) {
15691 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15693 this.footer.dataSource = this.store;
15694 this.footer.container = fctr;
15695 this.footer = Roo.factory(this.footer, Roo);
15696 fctr.insertFirst(this.el);
15698 // this is a bit insane - as the paging toolbar seems to detach the el..
15699 // dom.parentNode.parentNode.parentNode
15700 // they get detached?
15704 Roo.View.superclass.constructor.call(this);
15709 Roo.extend(Roo.View, Roo.util.Observable, {
15712 * @cfg {Roo.data.Store} store Data store to load data from.
15717 * @cfg {String|Roo.Element} el The container element.
15722 * @cfg {String|Roo.Template} tpl The template used by this View
15726 * @cfg {String} dataName the named area of the template to use as the data area
15727 * Works with domtemplates roo-name="name"
15731 * @cfg {String} selectedClass The css class to add to selected nodes
15733 selectedClass : "x-view-selected",
15735 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15740 * @cfg {String} text to display on mask (default Loading)
15744 * @cfg {Boolean} multiSelect Allow multiple selection
15746 multiSelect : false,
15748 * @cfg {Boolean} singleSelect Allow single selection
15750 singleSelect: false,
15753 * @cfg {Boolean} toggleSelect - selecting
15755 toggleSelect : false,
15758 * @cfg {Boolean} tickable - selecting
15763 * Returns the element this view is bound to.
15764 * @return {Roo.Element}
15766 getEl : function(){
15767 return this.wrapEl;
15773 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15775 refresh : function(){
15776 //Roo.log('refresh');
15779 // if we are using something like 'domtemplate', then
15780 // the what gets used is:
15781 // t.applySubtemplate(NAME, data, wrapping data..)
15782 // the outer template then get' applied with
15783 // the store 'extra data'
15784 // and the body get's added to the
15785 // roo-name="data" node?
15786 // <span class='roo-tpl-{name}'></span> ?????
15790 this.clearSelections();
15791 this.el.update("");
15793 var records = this.store.getRange();
15794 if(records.length < 1) {
15796 // is this valid?? = should it render a template??
15798 this.el.update(this.emptyText);
15802 if (this.dataName) {
15803 this.el.update(t.apply(this.store.meta)); //????
15804 el = this.el.child('.roo-tpl-' + this.dataName);
15807 for(var i = 0, len = records.length; i < len; i++){
15808 var data = this.prepareData(records[i].data, i, records[i]);
15809 this.fireEvent("preparedata", this, data, i, records[i]);
15811 var d = Roo.apply({}, data);
15814 Roo.apply(d, {'roo-id' : Roo.id()});
15818 Roo.each(this.parent.item, function(item){
15819 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15822 Roo.apply(d, {'roo-data-checked' : 'checked'});
15826 html[html.length] = Roo.util.Format.trim(
15828 t.applySubtemplate(this.dataName, d, this.store.meta) :
15835 el.update(html.join(""));
15836 this.nodes = el.dom.childNodes;
15837 this.updateIndexes(0);
15842 * Function to override to reformat the data that is sent to
15843 * the template for each node.
15844 * DEPRICATED - use the preparedata event handler.
15845 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15846 * a JSON object for an UpdateManager bound view).
15848 prepareData : function(data, index, record)
15850 this.fireEvent("preparedata", this, data, index, record);
15854 onUpdate : function(ds, record){
15855 // Roo.log('on update');
15856 this.clearSelections();
15857 var index = this.store.indexOf(record);
15858 var n = this.nodes[index];
15859 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15860 n.parentNode.removeChild(n);
15861 this.updateIndexes(index, index);
15867 onAdd : function(ds, records, index)
15869 //Roo.log(['on Add', ds, records, index] );
15870 this.clearSelections();
15871 if(this.nodes.length == 0){
15875 var n = this.nodes[index];
15876 for(var i = 0, len = records.length; i < len; i++){
15877 var d = this.prepareData(records[i].data, i, records[i]);
15879 this.tpl.insertBefore(n, d);
15882 this.tpl.append(this.el, d);
15885 this.updateIndexes(index);
15888 onRemove : function(ds, record, index){
15889 // Roo.log('onRemove');
15890 this.clearSelections();
15891 var el = this.dataName ?
15892 this.el.child('.roo-tpl-' + this.dataName) :
15895 el.dom.removeChild(this.nodes[index]);
15896 this.updateIndexes(index);
15900 * Refresh an individual node.
15901 * @param {Number} index
15903 refreshNode : function(index){
15904 this.onUpdate(this.store, this.store.getAt(index));
15907 updateIndexes : function(startIndex, endIndex){
15908 var ns = this.nodes;
15909 startIndex = startIndex || 0;
15910 endIndex = endIndex || ns.length - 1;
15911 for(var i = startIndex; i <= endIndex; i++){
15912 ns[i].nodeIndex = i;
15917 * Changes the data store this view uses and refresh the view.
15918 * @param {Store} store
15920 setStore : function(store, initial){
15921 if(!initial && this.store){
15922 this.store.un("datachanged", this.refresh);
15923 this.store.un("add", this.onAdd);
15924 this.store.un("remove", this.onRemove);
15925 this.store.un("update", this.onUpdate);
15926 this.store.un("clear", this.refresh);
15927 this.store.un("beforeload", this.onBeforeLoad);
15928 this.store.un("load", this.onLoad);
15929 this.store.un("loadexception", this.onLoad);
15933 store.on("datachanged", this.refresh, this);
15934 store.on("add", this.onAdd, this);
15935 store.on("remove", this.onRemove, this);
15936 store.on("update", this.onUpdate, this);
15937 store.on("clear", this.refresh, this);
15938 store.on("beforeload", this.onBeforeLoad, this);
15939 store.on("load", this.onLoad, this);
15940 store.on("loadexception", this.onLoad, this);
15948 * onbeforeLoad - masks the loading area.
15951 onBeforeLoad : function(store,opts)
15953 //Roo.log('onBeforeLoad');
15955 this.el.update("");
15957 this.el.mask(this.mask ? this.mask : "Loading" );
15959 onLoad : function ()
15966 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15967 * @param {HTMLElement} node
15968 * @return {HTMLElement} The template node
15970 findItemFromChild : function(node){
15971 var el = this.dataName ?
15972 this.el.child('.roo-tpl-' + this.dataName,true) :
15975 if(!node || node.parentNode == el){
15978 var p = node.parentNode;
15979 while(p && p != el){
15980 if(p.parentNode == el){
15989 onClick : function(e){
15990 var item = this.findItemFromChild(e.getTarget());
15992 var index = this.indexOf(item);
15993 if(this.onItemClick(item, index, e) !== false){
15994 this.fireEvent("click", this, index, item, e);
15997 this.clearSelections();
16002 onContextMenu : function(e){
16003 var item = this.findItemFromChild(e.getTarget());
16005 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16010 onDblClick : function(e){
16011 var item = this.findItemFromChild(e.getTarget());
16013 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16017 onItemClick : function(item, index, e)
16019 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16022 if (this.toggleSelect) {
16023 var m = this.isSelected(item) ? 'unselect' : 'select';
16026 _t[m](item, true, false);
16029 if(this.multiSelect || this.singleSelect){
16030 if(this.multiSelect && e.shiftKey && this.lastSelection){
16031 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16033 this.select(item, this.multiSelect && e.ctrlKey);
16034 this.lastSelection = item;
16037 if(!this.tickable){
16038 e.preventDefault();
16046 * Get the number of selected nodes.
16049 getSelectionCount : function(){
16050 return this.selections.length;
16054 * Get the currently selected nodes.
16055 * @return {Array} An array of HTMLElements
16057 getSelectedNodes : function(){
16058 return this.selections;
16062 * Get the indexes of the selected nodes.
16065 getSelectedIndexes : function(){
16066 var indexes = [], s = this.selections;
16067 for(var i = 0, len = s.length; i < len; i++){
16068 indexes.push(s[i].nodeIndex);
16074 * Clear all selections
16075 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16077 clearSelections : function(suppressEvent){
16078 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16079 this.cmp.elements = this.selections;
16080 this.cmp.removeClass(this.selectedClass);
16081 this.selections = [];
16082 if(!suppressEvent){
16083 this.fireEvent("selectionchange", this, this.selections);
16089 * Returns true if the passed node is selected
16090 * @param {HTMLElement/Number} node The node or node index
16091 * @return {Boolean}
16093 isSelected : function(node){
16094 var s = this.selections;
16098 node = this.getNode(node);
16099 return s.indexOf(node) !== -1;
16104 * @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
16105 * @param {Boolean} keepExisting (optional) true to keep existing selections
16106 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16108 select : function(nodeInfo, keepExisting, suppressEvent){
16109 if(nodeInfo instanceof Array){
16111 this.clearSelections(true);
16113 for(var i = 0, len = nodeInfo.length; i < len; i++){
16114 this.select(nodeInfo[i], true, true);
16118 var node = this.getNode(nodeInfo);
16119 if(!node || this.isSelected(node)){
16120 return; // already selected.
16123 this.clearSelections(true);
16126 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16127 Roo.fly(node).addClass(this.selectedClass);
16128 this.selections.push(node);
16129 if(!suppressEvent){
16130 this.fireEvent("selectionchange", this, this.selections);
16138 * @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
16139 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16140 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16142 unselect : function(nodeInfo, keepExisting, suppressEvent)
16144 if(nodeInfo instanceof Array){
16145 Roo.each(this.selections, function(s) {
16146 this.unselect(s, nodeInfo);
16150 var node = this.getNode(nodeInfo);
16151 if(!node || !this.isSelected(node)){
16152 //Roo.log("not selected");
16153 return; // not selected.
16157 Roo.each(this.selections, function(s) {
16159 Roo.fly(node).removeClass(this.selectedClass);
16166 this.selections= ns;
16167 this.fireEvent("selectionchange", this, this.selections);
16171 * Gets a template node.
16172 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16173 * @return {HTMLElement} The node or null if it wasn't found
16175 getNode : function(nodeInfo){
16176 if(typeof nodeInfo == "string"){
16177 return document.getElementById(nodeInfo);
16178 }else if(typeof nodeInfo == "number"){
16179 return this.nodes[nodeInfo];
16185 * Gets a range template nodes.
16186 * @param {Number} startIndex
16187 * @param {Number} endIndex
16188 * @return {Array} An array of nodes
16190 getNodes : function(start, end){
16191 var ns = this.nodes;
16192 start = start || 0;
16193 end = typeof end == "undefined" ? ns.length - 1 : end;
16196 for(var i = start; i <= end; i++){
16200 for(var i = start; i >= end; i--){
16208 * Finds the index of the passed node
16209 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16210 * @return {Number} The index of the node or -1
16212 indexOf : function(node){
16213 node = this.getNode(node);
16214 if(typeof node.nodeIndex == "number"){
16215 return node.nodeIndex;
16217 var ns = this.nodes;
16218 for(var i = 0, len = ns.length; i < len; i++){
16229 * based on jquery fullcalendar
16233 Roo.bootstrap = Roo.bootstrap || {};
16235 * @class Roo.bootstrap.Calendar
16236 * @extends Roo.bootstrap.Component
16237 * Bootstrap Calendar class
16238 * @cfg {Boolean} loadMask (true|false) default false
16239 * @cfg {Object} header generate the user specific header of the calendar, default false
16242 * Create a new Container
16243 * @param {Object} config The config object
16248 Roo.bootstrap.Calendar = function(config){
16249 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16253 * Fires when a date is selected
16254 * @param {DatePicker} this
16255 * @param {Date} date The selected date
16259 * @event monthchange
16260 * Fires when the displayed month changes
16261 * @param {DatePicker} this
16262 * @param {Date} date The selected month
16264 'monthchange': true,
16266 * @event evententer
16267 * Fires when mouse over an event
16268 * @param {Calendar} this
16269 * @param {event} Event
16271 'evententer': true,
16273 * @event eventleave
16274 * Fires when the mouse leaves an
16275 * @param {Calendar} this
16278 'eventleave': true,
16280 * @event eventclick
16281 * Fires when the mouse click an
16282 * @param {Calendar} this
16291 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16294 * @cfg {Number} startDay
16295 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16303 getAutoCreate : function(){
16306 var fc_button = function(name, corner, style, content ) {
16307 return Roo.apply({},{
16309 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16311 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16314 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16325 style : 'width:100%',
16332 cls : 'fc-header-left',
16334 fc_button('prev', 'left', 'arrow', '‹' ),
16335 fc_button('next', 'right', 'arrow', '›' ),
16336 { tag: 'span', cls: 'fc-header-space' },
16337 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16345 cls : 'fc-header-center',
16349 cls: 'fc-header-title',
16352 html : 'month / year'
16360 cls : 'fc-header-right',
16362 /* fc_button('month', 'left', '', 'month' ),
16363 fc_button('week', '', '', 'week' ),
16364 fc_button('day', 'right', '', 'day' )
16376 header = this.header;
16379 var cal_heads = function() {
16381 // fixme - handle this.
16383 for (var i =0; i < Date.dayNames.length; i++) {
16384 var d = Date.dayNames[i];
16387 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16388 html : d.substring(0,3)
16392 ret[0].cls += ' fc-first';
16393 ret[6].cls += ' fc-last';
16396 var cal_cell = function(n) {
16399 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16404 cls: 'fc-day-number',
16408 cls: 'fc-day-content',
16412 style: 'position: relative;' // height: 17px;
16424 var cal_rows = function() {
16427 for (var r = 0; r < 6; r++) {
16434 for (var i =0; i < Date.dayNames.length; i++) {
16435 var d = Date.dayNames[i];
16436 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16439 row.cn[0].cls+=' fc-first';
16440 row.cn[0].cn[0].style = 'min-height:90px';
16441 row.cn[6].cls+=' fc-last';
16445 ret[0].cls += ' fc-first';
16446 ret[4].cls += ' fc-prev-last';
16447 ret[5].cls += ' fc-last';
16454 cls: 'fc-border-separate',
16455 style : 'width:100%',
16463 cls : 'fc-first fc-last',
16481 cls : 'fc-content',
16482 style : "position: relative;",
16485 cls : 'fc-view fc-view-month fc-grid',
16486 style : 'position: relative',
16487 unselectable : 'on',
16490 cls : 'fc-event-container',
16491 style : 'position:absolute;z-index:8;top:0;left:0;'
16509 initEvents : function()
16512 throw "can not find store for calendar";
16518 style: "text-align:center",
16522 style: "background-color:white;width:50%;margin:250 auto",
16526 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16537 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16539 var size = this.el.select('.fc-content', true).first().getSize();
16540 this.maskEl.setSize(size.width, size.height);
16541 this.maskEl.enableDisplayMode("block");
16542 if(!this.loadMask){
16543 this.maskEl.hide();
16546 this.store = Roo.factory(this.store, Roo.data);
16547 this.store.on('load', this.onLoad, this);
16548 this.store.on('beforeload', this.onBeforeLoad, this);
16552 this.cells = this.el.select('.fc-day',true);
16553 //Roo.log(this.cells);
16554 this.textNodes = this.el.query('.fc-day-number');
16555 this.cells.addClassOnOver('fc-state-hover');
16557 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16558 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16559 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16560 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16562 this.on('monthchange', this.onMonthChange, this);
16564 this.update(new Date().clearTime());
16567 resize : function() {
16568 var sz = this.el.getSize();
16570 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16571 this.el.select('.fc-day-content div',true).setHeight(34);
16576 showPrevMonth : function(e){
16577 this.update(this.activeDate.add("mo", -1));
16579 showToday : function(e){
16580 this.update(new Date().clearTime());
16583 showNextMonth : function(e){
16584 this.update(this.activeDate.add("mo", 1));
16588 showPrevYear : function(){
16589 this.update(this.activeDate.add("y", -1));
16593 showNextYear : function(){
16594 this.update(this.activeDate.add("y", 1));
16599 update : function(date)
16601 var vd = this.activeDate;
16602 this.activeDate = date;
16603 // if(vd && this.el){
16604 // var t = date.getTime();
16605 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16606 // Roo.log('using add remove');
16608 // this.fireEvent('monthchange', this, date);
16610 // this.cells.removeClass("fc-state-highlight");
16611 // this.cells.each(function(c){
16612 // if(c.dateValue == t){
16613 // c.addClass("fc-state-highlight");
16614 // setTimeout(function(){
16615 // try{c.dom.firstChild.focus();}catch(e){}
16625 var days = date.getDaysInMonth();
16627 var firstOfMonth = date.getFirstDateOfMonth();
16628 var startingPos = firstOfMonth.getDay()-this.startDay;
16630 if(startingPos < this.startDay){
16634 var pm = date.add(Date.MONTH, -1);
16635 var prevStart = pm.getDaysInMonth()-startingPos;
16637 this.cells = this.el.select('.fc-day',true);
16638 this.textNodes = this.el.query('.fc-day-number');
16639 this.cells.addClassOnOver('fc-state-hover');
16641 var cells = this.cells.elements;
16642 var textEls = this.textNodes;
16644 Roo.each(cells, function(cell){
16645 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16648 days += startingPos;
16650 // convert everything to numbers so it's fast
16651 var day = 86400000;
16652 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16655 //Roo.log(prevStart);
16657 var today = new Date().clearTime().getTime();
16658 var sel = date.clearTime().getTime();
16659 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16660 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16661 var ddMatch = this.disabledDatesRE;
16662 var ddText = this.disabledDatesText;
16663 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16664 var ddaysText = this.disabledDaysText;
16665 var format = this.format;
16667 var setCellClass = function(cal, cell){
16671 //Roo.log('set Cell Class');
16673 var t = d.getTime();
16677 cell.dateValue = t;
16679 cell.className += " fc-today";
16680 cell.className += " fc-state-highlight";
16681 cell.title = cal.todayText;
16684 // disable highlight in other month..
16685 //cell.className += " fc-state-highlight";
16690 cell.className = " fc-state-disabled";
16691 cell.title = cal.minText;
16695 cell.className = " fc-state-disabled";
16696 cell.title = cal.maxText;
16700 if(ddays.indexOf(d.getDay()) != -1){
16701 cell.title = ddaysText;
16702 cell.className = " fc-state-disabled";
16705 if(ddMatch && format){
16706 var fvalue = d.dateFormat(format);
16707 if(ddMatch.test(fvalue)){
16708 cell.title = ddText.replace("%0", fvalue);
16709 cell.className = " fc-state-disabled";
16713 if (!cell.initialClassName) {
16714 cell.initialClassName = cell.dom.className;
16717 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16722 for(; i < startingPos; i++) {
16723 textEls[i].innerHTML = (++prevStart);
16724 d.setDate(d.getDate()+1);
16726 cells[i].className = "fc-past fc-other-month";
16727 setCellClass(this, cells[i]);
16732 for(; i < days; i++){
16733 intDay = i - startingPos + 1;
16734 textEls[i].innerHTML = (intDay);
16735 d.setDate(d.getDate()+1);
16737 cells[i].className = ''; // "x-date-active";
16738 setCellClass(this, cells[i]);
16742 for(; i < 42; i++) {
16743 textEls[i].innerHTML = (++extraDays);
16744 d.setDate(d.getDate()+1);
16746 cells[i].className = "fc-future fc-other-month";
16747 setCellClass(this, cells[i]);
16750 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16752 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16754 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16755 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16757 if(totalRows != 6){
16758 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16759 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16762 this.fireEvent('monthchange', this, date);
16766 if(!this.internalRender){
16767 var main = this.el.dom.firstChild;
16768 var w = main.offsetWidth;
16769 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16770 Roo.fly(main).setWidth(w);
16771 this.internalRender = true;
16772 // opera does not respect the auto grow header center column
16773 // then, after it gets a width opera refuses to recalculate
16774 // without a second pass
16775 if(Roo.isOpera && !this.secondPass){
16776 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16777 this.secondPass = true;
16778 this.update.defer(10, this, [date]);
16785 findCell : function(dt) {
16786 dt = dt.clearTime().getTime();
16788 this.cells.each(function(c){
16789 //Roo.log("check " +c.dateValue + '?=' + dt);
16790 if(c.dateValue == dt){
16800 findCells : function(ev) {
16801 var s = ev.start.clone().clearTime().getTime();
16803 var e= ev.end.clone().clearTime().getTime();
16806 this.cells.each(function(c){
16807 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16809 if(c.dateValue > e){
16812 if(c.dateValue < s){
16821 // findBestRow: function(cells)
16825 // for (var i =0 ; i < cells.length;i++) {
16826 // ret = Math.max(cells[i].rows || 0,ret);
16833 addItem : function(ev)
16835 // look for vertical location slot in
16836 var cells = this.findCells(ev);
16838 // ev.row = this.findBestRow(cells);
16840 // work out the location.
16844 for(var i =0; i < cells.length; i++) {
16846 cells[i].row = cells[0].row;
16849 cells[i].row = cells[i].row + 1;
16859 if (crow.start.getY() == cells[i].getY()) {
16861 crow.end = cells[i];
16878 cells[0].events.push(ev);
16880 this.calevents.push(ev);
16883 clearEvents: function() {
16885 if(!this.calevents){
16889 Roo.each(this.cells.elements, function(c){
16895 Roo.each(this.calevents, function(e) {
16896 Roo.each(e.els, function(el) {
16897 el.un('mouseenter' ,this.onEventEnter, this);
16898 el.un('mouseleave' ,this.onEventLeave, this);
16903 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16909 renderEvents: function()
16913 this.cells.each(function(c) {
16922 if(c.row != c.events.length){
16923 r = 4 - (4 - (c.row - c.events.length));
16926 c.events = ev.slice(0, r);
16927 c.more = ev.slice(r);
16929 if(c.more.length && c.more.length == 1){
16930 c.events.push(c.more.pop());
16933 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16937 this.cells.each(function(c) {
16939 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16942 for (var e = 0; e < c.events.length; e++){
16943 var ev = c.events[e];
16944 var rows = ev.rows;
16946 for(var i = 0; i < rows.length; i++) {
16948 // how many rows should it span..
16951 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16952 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16954 unselectable : "on",
16957 cls: 'fc-event-inner',
16961 // cls: 'fc-event-time',
16962 // html : cells.length > 1 ? '' : ev.time
16966 cls: 'fc-event-title',
16967 html : String.format('{0}', ev.title)
16974 cls: 'ui-resizable-handle ui-resizable-e',
16975 html : '  '
16982 cfg.cls += ' fc-event-start';
16984 if ((i+1) == rows.length) {
16985 cfg.cls += ' fc-event-end';
16988 var ctr = _this.el.select('.fc-event-container',true).first();
16989 var cg = ctr.createChild(cfg);
16991 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16992 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16994 var r = (c.more.length) ? 1 : 0;
16995 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16996 cg.setWidth(ebox.right - sbox.x -2);
16998 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16999 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17000 cg.on('click', _this.onEventClick, _this, ev);
17011 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17012 style : 'position: absolute',
17013 unselectable : "on",
17016 cls: 'fc-event-inner',
17020 cls: 'fc-event-title',
17028 cls: 'ui-resizable-handle ui-resizable-e',
17029 html : '  '
17035 var ctr = _this.el.select('.fc-event-container',true).first();
17036 var cg = ctr.createChild(cfg);
17038 var sbox = c.select('.fc-day-content',true).first().getBox();
17039 var ebox = c.select('.fc-day-content',true).first().getBox();
17041 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17042 cg.setWidth(ebox.right - sbox.x -2);
17044 cg.on('click', _this.onMoreEventClick, _this, c.more);
17054 onEventEnter: function (e, el,event,d) {
17055 this.fireEvent('evententer', this, el, event);
17058 onEventLeave: function (e, el,event,d) {
17059 this.fireEvent('eventleave', this, el, event);
17062 onEventClick: function (e, el,event,d) {
17063 this.fireEvent('eventclick', this, el, event);
17066 onMonthChange: function () {
17070 onMoreEventClick: function(e, el, more)
17074 this.calpopover.placement = 'right';
17075 this.calpopover.setTitle('More');
17077 this.calpopover.setContent('');
17079 var ctr = this.calpopover.el.select('.popover-content', true).first();
17081 Roo.each(more, function(m){
17083 cls : 'fc-event-hori fc-event-draggable',
17086 var cg = ctr.createChild(cfg);
17088 cg.on('click', _this.onEventClick, _this, m);
17091 this.calpopover.show(el);
17096 onLoad: function ()
17098 this.calevents = [];
17101 if(this.store.getCount() > 0){
17102 this.store.data.each(function(d){
17105 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17106 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17107 time : d.data.start_time,
17108 title : d.data.title,
17109 description : d.data.description,
17110 venue : d.data.venue
17115 this.renderEvents();
17117 if(this.calevents.length && this.loadMask){
17118 this.maskEl.hide();
17122 onBeforeLoad: function()
17124 this.clearEvents();
17126 this.maskEl.show();
17140 * @class Roo.bootstrap.Popover
17141 * @extends Roo.bootstrap.Component
17142 * Bootstrap Popover class
17143 * @cfg {String} html contents of the popover (or false to use children..)
17144 * @cfg {String} title of popover (or false to hide)
17145 * @cfg {String} placement how it is placed
17146 * @cfg {String} trigger click || hover (or false to trigger manually)
17147 * @cfg {String} over what (parent or false to trigger manually.)
17148 * @cfg {Number} delay - delay before showing
17151 * Create a new Popover
17152 * @param {Object} config The config object
17155 Roo.bootstrap.Popover = function(config){
17156 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17162 * After the popover show
17164 * @param {Roo.bootstrap.Popover} this
17169 * After the popover hide
17171 * @param {Roo.bootstrap.Popover} this
17177 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17179 title: 'Fill in a title',
17182 placement : 'right',
17183 trigger : 'hover', // hover
17189 can_build_overlaid : false,
17191 getChildContainer : function()
17193 return this.el.select('.popover-content',true).first();
17196 getAutoCreate : function(){
17199 cls : 'popover roo-dynamic',
17200 style: 'display:block',
17206 cls : 'popover-inner',
17210 cls: 'popover-title',
17214 cls : 'popover-content',
17225 setTitle: function(str)
17228 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17230 setContent: function(str)
17233 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17235 // as it get's added to the bottom of the page.
17236 onRender : function(ct, position)
17238 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17240 var cfg = Roo.apply({}, this.getAutoCreate());
17244 cfg.cls += ' ' + this.cls;
17247 cfg.style = this.style;
17249 //Roo.log("adding to ");
17250 this.el = Roo.get(document.body).createChild(cfg, position);
17251 // Roo.log(this.el);
17256 initEvents : function()
17258 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17259 this.el.enableDisplayMode('block');
17261 if (this.over === false) {
17264 if (this.triggers === false) {
17267 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17268 var triggers = this.trigger ? this.trigger.split(' ') : [];
17269 Roo.each(triggers, function(trigger) {
17271 if (trigger == 'click') {
17272 on_el.on('click', this.toggle, this);
17273 } else if (trigger != 'manual') {
17274 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17275 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17277 on_el.on(eventIn ,this.enter, this);
17278 on_el.on(eventOut, this.leave, this);
17289 toggle : function () {
17290 this.hoverState == 'in' ? this.leave() : this.enter();
17293 enter : function () {
17295 clearTimeout(this.timeout);
17297 this.hoverState = 'in';
17299 if (!this.delay || !this.delay.show) {
17304 this.timeout = setTimeout(function () {
17305 if (_t.hoverState == 'in') {
17308 }, this.delay.show)
17311 leave : function() {
17312 clearTimeout(this.timeout);
17314 this.hoverState = 'out';
17316 if (!this.delay || !this.delay.hide) {
17321 this.timeout = setTimeout(function () {
17322 if (_t.hoverState == 'out') {
17325 }, this.delay.hide)
17328 show : function (on_el)
17331 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17335 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17336 if (this.html !== false) {
17337 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17339 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17340 if (!this.title.length) {
17341 this.el.select('.popover-title',true).hide();
17344 var placement = typeof this.placement == 'function' ?
17345 this.placement.call(this, this.el, on_el) :
17348 var autoToken = /\s?auto?\s?/i;
17349 var autoPlace = autoToken.test(placement);
17351 placement = placement.replace(autoToken, '') || 'top';
17355 //this.el.setXY([0,0]);
17357 this.el.dom.style.display='block';
17358 this.el.addClass(placement);
17360 //this.el.appendTo(on_el);
17362 var p = this.getPosition();
17363 var box = this.el.getBox();
17368 var align = Roo.bootstrap.Popover.alignment[placement];
17371 this.el.alignTo(on_el, align[0],align[1]);
17372 //var arrow = this.el.select('.arrow',true).first();
17373 //arrow.set(align[2],
17375 this.el.addClass('in');
17378 if (this.el.hasClass('fade')) {
17382 this.hoverState = 'in';
17384 this.fireEvent('show', this);
17389 this.el.setXY([0,0]);
17390 this.el.removeClass('in');
17392 this.hoverState = null;
17394 this.fireEvent('hide', this);
17399 Roo.bootstrap.Popover.alignment = {
17400 'left' : ['r-l', [-10,0], 'right'],
17401 'right' : ['l-r', [10,0], 'left'],
17402 'bottom' : ['t-b', [0,10], 'top'],
17403 'top' : [ 'b-t', [0,-10], 'bottom']
17414 * @class Roo.bootstrap.Progress
17415 * @extends Roo.bootstrap.Component
17416 * Bootstrap Progress class
17417 * @cfg {Boolean} striped striped of the progress bar
17418 * @cfg {Boolean} active animated of the progress bar
17422 * Create a new Progress
17423 * @param {Object} config The config object
17426 Roo.bootstrap.Progress = function(config){
17427 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17430 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17435 getAutoCreate : function(){
17443 cfg.cls += ' progress-striped';
17447 cfg.cls += ' active';
17466 * @class Roo.bootstrap.ProgressBar
17467 * @extends Roo.bootstrap.Component
17468 * Bootstrap ProgressBar class
17469 * @cfg {Number} aria_valuenow aria-value now
17470 * @cfg {Number} aria_valuemin aria-value min
17471 * @cfg {Number} aria_valuemax aria-value max
17472 * @cfg {String} label label for the progress bar
17473 * @cfg {String} panel (success | info | warning | danger )
17474 * @cfg {String} role role of the progress bar
17475 * @cfg {String} sr_only text
17479 * Create a new ProgressBar
17480 * @param {Object} config The config object
17483 Roo.bootstrap.ProgressBar = function(config){
17484 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17487 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17491 aria_valuemax : 100,
17497 getAutoCreate : function()
17502 cls: 'progress-bar',
17503 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17515 cfg.role = this.role;
17518 if(this.aria_valuenow){
17519 cfg['aria-valuenow'] = this.aria_valuenow;
17522 if(this.aria_valuemin){
17523 cfg['aria-valuemin'] = this.aria_valuemin;
17526 if(this.aria_valuemax){
17527 cfg['aria-valuemax'] = this.aria_valuemax;
17530 if(this.label && !this.sr_only){
17531 cfg.html = this.label;
17535 cfg.cls += ' progress-bar-' + this.panel;
17541 update : function(aria_valuenow)
17543 this.aria_valuenow = aria_valuenow;
17545 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17560 * @class Roo.bootstrap.TabGroup
17561 * @extends Roo.bootstrap.Column
17562 * Bootstrap Column class
17563 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17564 * @cfg {Boolean} carousel true to make the group behave like a carousel
17565 * @cfg {Boolean} bullets show bullets for the panels
17566 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17567 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17568 * @cfg {Boolean} showarrow (true|false) show arrow default true
17571 * Create a new TabGroup
17572 * @param {Object} config The config object
17575 Roo.bootstrap.TabGroup = function(config){
17576 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17578 this.navId = Roo.id();
17581 Roo.bootstrap.TabGroup.register(this);
17585 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17588 transition : false,
17593 slideOnTouch : false,
17596 getAutoCreate : function()
17598 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17600 cfg.cls += ' tab-content';
17602 if (this.carousel) {
17603 cfg.cls += ' carousel slide';
17606 cls : 'carousel-inner',
17610 if(this.bullets && !Roo.isTouch){
17613 cls : 'carousel-bullets',
17617 if(this.bullets_cls){
17618 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17625 cfg.cn[0].cn.push(bullets);
17628 if(this.showarrow){
17629 cfg.cn[0].cn.push({
17631 class : 'carousel-arrow',
17635 class : 'carousel-prev',
17639 class : 'fa fa-chevron-left'
17645 class : 'carousel-next',
17649 class : 'fa fa-chevron-right'
17662 initEvents: function()
17664 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17665 // this.el.on("touchstart", this.onTouchStart, this);
17668 if(this.autoslide){
17671 this.slideFn = window.setInterval(function() {
17672 _this.showPanelNext();
17676 if(this.showarrow){
17677 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17678 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17684 // onTouchStart : function(e, el, o)
17686 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17690 // this.showPanelNext();
17694 getChildContainer : function()
17696 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17700 * register a Navigation item
17701 * @param {Roo.bootstrap.NavItem} the navitem to add
17703 register : function(item)
17705 this.tabs.push( item);
17706 item.navId = this.navId; // not really needed..
17711 getActivePanel : function()
17714 Roo.each(this.tabs, function(t) {
17724 getPanelByName : function(n)
17727 Roo.each(this.tabs, function(t) {
17728 if (t.tabId == n) {
17736 indexOfPanel : function(p)
17739 Roo.each(this.tabs, function(t,i) {
17740 if (t.tabId == p.tabId) {
17749 * show a specific panel
17750 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17751 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17753 showPanel : function (pan)
17755 if(this.transition || typeof(pan) == 'undefined'){
17756 Roo.log("waiting for the transitionend");
17760 if (typeof(pan) == 'number') {
17761 pan = this.tabs[pan];
17764 if (typeof(pan) == 'string') {
17765 pan = this.getPanelByName(pan);
17768 var cur = this.getActivePanel();
17771 Roo.log('pan or acitve pan is undefined');
17775 if (pan.tabId == this.getActivePanel().tabId) {
17779 if (false === cur.fireEvent('beforedeactivate')) {
17783 if(this.bullets > 0 && !Roo.isTouch){
17784 this.setActiveBullet(this.indexOfPanel(pan));
17787 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17789 this.transition = true;
17790 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17791 var lr = dir == 'next' ? 'left' : 'right';
17792 pan.el.addClass(dir); // or prev
17793 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17794 cur.el.addClass(lr); // or right
17795 pan.el.addClass(lr);
17798 cur.el.on('transitionend', function() {
17799 Roo.log("trans end?");
17801 pan.el.removeClass([lr,dir]);
17802 pan.setActive(true);
17804 cur.el.removeClass([lr]);
17805 cur.setActive(false);
17807 _this.transition = false;
17809 }, this, { single: true } );
17814 cur.setActive(false);
17815 pan.setActive(true);
17820 showPanelNext : function()
17822 var i = this.indexOfPanel(this.getActivePanel());
17824 if (i >= this.tabs.length - 1 && !this.autoslide) {
17828 if (i >= this.tabs.length - 1 && this.autoslide) {
17832 this.showPanel(this.tabs[i+1]);
17835 showPanelPrev : function()
17837 var i = this.indexOfPanel(this.getActivePanel());
17839 if (i < 1 && !this.autoslide) {
17843 if (i < 1 && this.autoslide) {
17844 i = this.tabs.length;
17847 this.showPanel(this.tabs[i-1]);
17851 addBullet: function()
17853 if(!this.bullets || Roo.isTouch){
17856 var ctr = this.el.select('.carousel-bullets',true).first();
17857 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17858 var bullet = ctr.createChild({
17859 cls : 'bullet bullet-' + i
17860 },ctr.dom.lastChild);
17865 bullet.on('click', (function(e, el, o, ii, t){
17867 e.preventDefault();
17869 this.showPanel(ii);
17871 if(this.autoslide && this.slideFn){
17872 clearInterval(this.slideFn);
17873 this.slideFn = window.setInterval(function() {
17874 _this.showPanelNext();
17878 }).createDelegate(this, [i, bullet], true));
17883 setActiveBullet : function(i)
17889 Roo.each(this.el.select('.bullet', true).elements, function(el){
17890 el.removeClass('selected');
17893 var bullet = this.el.select('.bullet-' + i, true).first();
17899 bullet.addClass('selected');
17910 Roo.apply(Roo.bootstrap.TabGroup, {
17914 * register a Navigation Group
17915 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17917 register : function(navgrp)
17919 this.groups[navgrp.navId] = navgrp;
17923 * fetch a Navigation Group based on the navigation ID
17924 * if one does not exist , it will get created.
17925 * @param {string} the navgroup to add
17926 * @returns {Roo.bootstrap.NavGroup} the navgroup
17928 get: function(navId) {
17929 if (typeof(this.groups[navId]) == 'undefined') {
17930 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17932 return this.groups[navId] ;
17947 * @class Roo.bootstrap.TabPanel
17948 * @extends Roo.bootstrap.Component
17949 * Bootstrap TabPanel class
17950 * @cfg {Boolean} active panel active
17951 * @cfg {String} html panel content
17952 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17953 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17954 * @cfg {String} href click to link..
17958 * Create a new TabPanel
17959 * @param {Object} config The config object
17962 Roo.bootstrap.TabPanel = function(config){
17963 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17967 * Fires when the active status changes
17968 * @param {Roo.bootstrap.TabPanel} this
17969 * @param {Boolean} state the new state
17974 * @event beforedeactivate
17975 * Fires before a tab is de-activated - can be used to do validation on a form.
17976 * @param {Roo.bootstrap.TabPanel} this
17977 * @return {Boolean} false if there is an error
17980 'beforedeactivate': true
17983 this.tabId = this.tabId || Roo.id();
17987 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17995 getAutoCreate : function(){
17998 // item is needed for carousel - not sure if it has any effect otherwise
17999 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18000 html: this.html || ''
18004 cfg.cls += ' active';
18008 cfg.tabId = this.tabId;
18015 initEvents: function()
18017 var p = this.parent();
18019 this.navId = this.navId || p.navId;
18021 if (typeof(this.navId) != 'undefined') {
18022 // not really needed.. but just in case.. parent should be a NavGroup.
18023 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18027 var i = tg.tabs.length - 1;
18029 if(this.active && tg.bullets > 0 && i < tg.bullets){
18030 tg.setActiveBullet(i);
18034 this.el.on('click', this.onClick, this);
18037 this.el.on("touchstart", this.onTouchStart, this);
18038 this.el.on("touchmove", this.onTouchMove, this);
18039 this.el.on("touchend", this.onTouchEnd, this);
18044 onRender : function(ct, position)
18046 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18049 setActive : function(state)
18051 Roo.log("panel - set active " + this.tabId + "=" + state);
18053 this.active = state;
18055 this.el.removeClass('active');
18057 } else if (!this.el.hasClass('active')) {
18058 this.el.addClass('active');
18061 this.fireEvent('changed', this, state);
18064 onClick : function(e)
18066 e.preventDefault();
18068 if(!this.href.length){
18072 window.location.href = this.href;
18081 onTouchStart : function(e)
18083 this.swiping = false;
18085 this.startX = e.browserEvent.touches[0].clientX;
18086 this.startY = e.browserEvent.touches[0].clientY;
18089 onTouchMove : function(e)
18091 this.swiping = true;
18093 this.endX = e.browserEvent.touches[0].clientX;
18094 this.endY = e.browserEvent.touches[0].clientY;
18097 onTouchEnd : function(e)
18104 var tabGroup = this.parent();
18106 if(this.endX > this.startX){ // swiping right
18107 tabGroup.showPanelPrev();
18111 if(this.startX > this.endX){ // swiping left
18112 tabGroup.showPanelNext();
18131 * @class Roo.bootstrap.DateField
18132 * @extends Roo.bootstrap.Input
18133 * Bootstrap DateField class
18134 * @cfg {Number} weekStart default 0
18135 * @cfg {String} viewMode default empty, (months|years)
18136 * @cfg {String} minViewMode default empty, (months|years)
18137 * @cfg {Number} startDate default -Infinity
18138 * @cfg {Number} endDate default Infinity
18139 * @cfg {Boolean} todayHighlight default false
18140 * @cfg {Boolean} todayBtn default false
18141 * @cfg {Boolean} calendarWeeks default false
18142 * @cfg {Object} daysOfWeekDisabled default empty
18143 * @cfg {Boolean} singleMode default false (true | false)
18145 * @cfg {Boolean} keyboardNavigation default true
18146 * @cfg {String} language default en
18149 * Create a new DateField
18150 * @param {Object} config The config object
18153 Roo.bootstrap.DateField = function(config){
18154 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18158 * Fires when this field show.
18159 * @param {Roo.bootstrap.DateField} this
18160 * @param {Mixed} date The date value
18165 * Fires when this field hide.
18166 * @param {Roo.bootstrap.DateField} this
18167 * @param {Mixed} date The date value
18172 * Fires when select a date.
18173 * @param {Roo.bootstrap.DateField} this
18174 * @param {Mixed} date The date value
18178 * @event beforeselect
18179 * Fires when before select a date.
18180 * @param {Roo.bootstrap.DateField} this
18181 * @param {Mixed} date The date value
18183 beforeselect : true
18187 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18190 * @cfg {String} format
18191 * The default date format string which can be overriden for localization support. The format must be
18192 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18196 * @cfg {String} altFormats
18197 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18198 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18200 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18208 todayHighlight : false,
18214 keyboardNavigation: true,
18216 calendarWeeks: false,
18218 startDate: -Infinity,
18222 daysOfWeekDisabled: [],
18226 singleMode : false,
18228 UTCDate: function()
18230 return new Date(Date.UTC.apply(Date, arguments));
18233 UTCToday: function()
18235 var today = new Date();
18236 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18239 getDate: function() {
18240 var d = this.getUTCDate();
18241 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18244 getUTCDate: function() {
18248 setDate: function(d) {
18249 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18252 setUTCDate: function(d) {
18254 this.setValue(this.formatDate(this.date));
18257 onRender: function(ct, position)
18260 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18262 this.language = this.language || 'en';
18263 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18264 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18266 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18267 this.format = this.format || 'm/d/y';
18268 this.isInline = false;
18269 this.isInput = true;
18270 this.component = this.el.select('.add-on', true).first() || false;
18271 this.component = (this.component && this.component.length === 0) ? false : this.component;
18272 this.hasInput = this.component && this.inputEl().length;
18274 if (typeof(this.minViewMode === 'string')) {
18275 switch (this.minViewMode) {
18277 this.minViewMode = 1;
18280 this.minViewMode = 2;
18283 this.minViewMode = 0;
18288 if (typeof(this.viewMode === 'string')) {
18289 switch (this.viewMode) {
18302 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18304 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18306 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18308 this.picker().on('mousedown', this.onMousedown, this);
18309 this.picker().on('click', this.onClick, this);
18311 this.picker().addClass('datepicker-dropdown');
18313 this.startViewMode = this.viewMode;
18315 if(this.singleMode){
18316 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18317 v.setVisibilityMode(Roo.Element.DISPLAY);
18321 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18322 v.setStyle('width', '189px');
18326 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18327 if(!this.calendarWeeks){
18332 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18333 v.attr('colspan', function(i, val){
18334 return parseInt(val) + 1;
18339 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18341 this.setStartDate(this.startDate);
18342 this.setEndDate(this.endDate);
18344 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18351 if(this.isInline) {
18356 picker : function()
18358 return this.pickerEl;
18359 // return this.el.select('.datepicker', true).first();
18362 fillDow: function()
18364 var dowCnt = this.weekStart;
18373 if(this.calendarWeeks){
18381 while (dowCnt < this.weekStart + 7) {
18385 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18389 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18392 fillMonths: function()
18395 var months = this.picker().select('>.datepicker-months td', true).first();
18397 months.dom.innerHTML = '';
18403 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18406 months.createChild(month);
18413 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;
18415 if (this.date < this.startDate) {
18416 this.viewDate = new Date(this.startDate);
18417 } else if (this.date > this.endDate) {
18418 this.viewDate = new Date(this.endDate);
18420 this.viewDate = new Date(this.date);
18428 var d = new Date(this.viewDate),
18429 year = d.getUTCFullYear(),
18430 month = d.getUTCMonth(),
18431 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18432 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18433 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18434 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18435 currentDate = this.date && this.date.valueOf(),
18436 today = this.UTCToday();
18438 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18440 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18442 // this.picker.select('>tfoot th.today').
18443 // .text(dates[this.language].today)
18444 // .toggle(this.todayBtn !== false);
18446 this.updateNavArrows();
18449 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18451 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18453 prevMonth.setUTCDate(day);
18455 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18457 var nextMonth = new Date(prevMonth);
18459 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18461 nextMonth = nextMonth.valueOf();
18463 var fillMonths = false;
18465 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18467 while(prevMonth.valueOf() < nextMonth) {
18470 if (prevMonth.getUTCDay() === this.weekStart) {
18472 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18480 if(this.calendarWeeks){
18481 // ISO 8601: First week contains first thursday.
18482 // ISO also states week starts on Monday, but we can be more abstract here.
18484 // Start of current week: based on weekstart/current date
18485 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18486 // Thursday of this week
18487 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18488 // First Thursday of year, year from thursday
18489 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18490 // Calendar week: ms between thursdays, div ms per day, div 7 days
18491 calWeek = (th - yth) / 864e5 / 7 + 1;
18493 fillMonths.cn.push({
18501 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18503 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18506 if (this.todayHighlight &&
18507 prevMonth.getUTCFullYear() == today.getFullYear() &&
18508 prevMonth.getUTCMonth() == today.getMonth() &&
18509 prevMonth.getUTCDate() == today.getDate()) {
18510 clsName += ' today';
18513 if (currentDate && prevMonth.valueOf() === currentDate) {
18514 clsName += ' active';
18517 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18518 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18519 clsName += ' disabled';
18522 fillMonths.cn.push({
18524 cls: 'day ' + clsName,
18525 html: prevMonth.getDate()
18528 prevMonth.setDate(prevMonth.getDate()+1);
18531 var currentYear = this.date && this.date.getUTCFullYear();
18532 var currentMonth = this.date && this.date.getUTCMonth();
18534 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18536 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18537 v.removeClass('active');
18539 if(currentYear === year && k === currentMonth){
18540 v.addClass('active');
18543 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18544 v.addClass('disabled');
18550 year = parseInt(year/10, 10) * 10;
18552 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18554 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18557 for (var i = -1; i < 11; i++) {
18558 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18560 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18568 showMode: function(dir)
18571 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18574 Roo.each(this.picker().select('>div',true).elements, function(v){
18575 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18578 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18583 if(this.isInline) {
18587 this.picker().removeClass(['bottom', 'top']);
18589 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18591 * place to the top of element!
18595 this.picker().addClass('top');
18596 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18601 this.picker().addClass('bottom');
18603 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18606 parseDate : function(value)
18608 if(!value || value instanceof Date){
18611 var v = Date.parseDate(value, this.format);
18612 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18613 v = Date.parseDate(value, 'Y-m-d');
18615 if(!v && this.altFormats){
18616 if(!this.altFormatsArray){
18617 this.altFormatsArray = this.altFormats.split("|");
18619 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18620 v = Date.parseDate(value, this.altFormatsArray[i]);
18626 formatDate : function(date, fmt)
18628 return (!date || !(date instanceof Date)) ?
18629 date : date.dateFormat(fmt || this.format);
18632 onFocus : function()
18634 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18638 onBlur : function()
18640 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18642 var d = this.inputEl().getValue();
18651 this.picker().show();
18655 this.fireEvent('show', this, this.date);
18660 if(this.isInline) {
18663 this.picker().hide();
18664 this.viewMode = this.startViewMode;
18667 this.fireEvent('hide', this, this.date);
18671 onMousedown: function(e)
18673 e.stopPropagation();
18674 e.preventDefault();
18679 Roo.bootstrap.DateField.superclass.keyup.call(this);
18683 setValue: function(v)
18685 if(this.fireEvent('beforeselect', this, v) !== false){
18686 var d = new Date(this.parseDate(v) ).clearTime();
18688 if(isNaN(d.getTime())){
18689 this.date = this.viewDate = '';
18690 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18694 v = this.formatDate(d);
18696 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18698 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18702 this.fireEvent('select', this, this.date);
18706 getValue: function()
18708 return this.formatDate(this.date);
18711 fireKey: function(e)
18713 if (!this.picker().isVisible()){
18714 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18720 var dateChanged = false,
18722 newDate, newViewDate;
18727 e.preventDefault();
18731 if (!this.keyboardNavigation) {
18734 dir = e.keyCode == 37 ? -1 : 1;
18737 newDate = this.moveYear(this.date, dir);
18738 newViewDate = this.moveYear(this.viewDate, dir);
18739 } else if (e.shiftKey){
18740 newDate = this.moveMonth(this.date, dir);
18741 newViewDate = this.moveMonth(this.viewDate, dir);
18743 newDate = new Date(this.date);
18744 newDate.setUTCDate(this.date.getUTCDate() + dir);
18745 newViewDate = new Date(this.viewDate);
18746 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18748 if (this.dateWithinRange(newDate)){
18749 this.date = newDate;
18750 this.viewDate = newViewDate;
18751 this.setValue(this.formatDate(this.date));
18753 e.preventDefault();
18754 dateChanged = true;
18759 if (!this.keyboardNavigation) {
18762 dir = e.keyCode == 38 ? -1 : 1;
18764 newDate = this.moveYear(this.date, dir);
18765 newViewDate = this.moveYear(this.viewDate, dir);
18766 } else if (e.shiftKey){
18767 newDate = this.moveMonth(this.date, dir);
18768 newViewDate = this.moveMonth(this.viewDate, dir);
18770 newDate = new Date(this.date);
18771 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18772 newViewDate = new Date(this.viewDate);
18773 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18775 if (this.dateWithinRange(newDate)){
18776 this.date = newDate;
18777 this.viewDate = newViewDate;
18778 this.setValue(this.formatDate(this.date));
18780 e.preventDefault();
18781 dateChanged = true;
18785 this.setValue(this.formatDate(this.date));
18787 e.preventDefault();
18790 this.setValue(this.formatDate(this.date));
18804 onClick: function(e)
18806 e.stopPropagation();
18807 e.preventDefault();
18809 var target = e.getTarget();
18811 if(target.nodeName.toLowerCase() === 'i'){
18812 target = Roo.get(target).dom.parentNode;
18815 var nodeName = target.nodeName;
18816 var className = target.className;
18817 var html = target.innerHTML;
18818 //Roo.log(nodeName);
18820 switch(nodeName.toLowerCase()) {
18822 switch(className) {
18828 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18829 switch(this.viewMode){
18831 this.viewDate = this.moveMonth(this.viewDate, dir);
18835 this.viewDate = this.moveYear(this.viewDate, dir);
18841 var date = new Date();
18842 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18844 this.setValue(this.formatDate(this.date));
18851 if (className.indexOf('disabled') < 0) {
18852 this.viewDate.setUTCDate(1);
18853 if (className.indexOf('month') > -1) {
18854 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18856 var year = parseInt(html, 10) || 0;
18857 this.viewDate.setUTCFullYear(year);
18861 if(this.singleMode){
18862 this.setValue(this.formatDate(this.viewDate));
18873 //Roo.log(className);
18874 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18875 var day = parseInt(html, 10) || 1;
18876 var year = this.viewDate.getUTCFullYear(),
18877 month = this.viewDate.getUTCMonth();
18879 if (className.indexOf('old') > -1) {
18886 } else if (className.indexOf('new') > -1) {
18894 //Roo.log([year,month,day]);
18895 this.date = this.UTCDate(year, month, day,0,0,0,0);
18896 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18898 //Roo.log(this.formatDate(this.date));
18899 this.setValue(this.formatDate(this.date));
18906 setStartDate: function(startDate)
18908 this.startDate = startDate || -Infinity;
18909 if (this.startDate !== -Infinity) {
18910 this.startDate = this.parseDate(this.startDate);
18913 this.updateNavArrows();
18916 setEndDate: function(endDate)
18918 this.endDate = endDate || Infinity;
18919 if (this.endDate !== Infinity) {
18920 this.endDate = this.parseDate(this.endDate);
18923 this.updateNavArrows();
18926 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18928 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18929 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18930 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18932 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18933 return parseInt(d, 10);
18936 this.updateNavArrows();
18939 updateNavArrows: function()
18941 if(this.singleMode){
18945 var d = new Date(this.viewDate),
18946 year = d.getUTCFullYear(),
18947 month = d.getUTCMonth();
18949 Roo.each(this.picker().select('.prev', true).elements, function(v){
18951 switch (this.viewMode) {
18954 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18960 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18967 Roo.each(this.picker().select('.next', true).elements, function(v){
18969 switch (this.viewMode) {
18972 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18978 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18986 moveMonth: function(date, dir)
18991 var new_date = new Date(date.valueOf()),
18992 day = new_date.getUTCDate(),
18993 month = new_date.getUTCMonth(),
18994 mag = Math.abs(dir),
18996 dir = dir > 0 ? 1 : -1;
18999 // If going back one month, make sure month is not current month
19000 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19002 return new_date.getUTCMonth() == month;
19004 // If going forward one month, make sure month is as expected
19005 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19007 return new_date.getUTCMonth() != new_month;
19009 new_month = month + dir;
19010 new_date.setUTCMonth(new_month);
19011 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19012 if (new_month < 0 || new_month > 11) {
19013 new_month = (new_month + 12) % 12;
19016 // For magnitudes >1, move one month at a time...
19017 for (var i=0; i<mag; i++) {
19018 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19019 new_date = this.moveMonth(new_date, dir);
19021 // ...then reset the day, keeping it in the new month
19022 new_month = new_date.getUTCMonth();
19023 new_date.setUTCDate(day);
19025 return new_month != new_date.getUTCMonth();
19028 // Common date-resetting loop -- if date is beyond end of month, make it
19031 new_date.setUTCDate(--day);
19032 new_date.setUTCMonth(new_month);
19037 moveYear: function(date, dir)
19039 return this.moveMonth(date, dir*12);
19042 dateWithinRange: function(date)
19044 return date >= this.startDate && date <= this.endDate;
19050 this.picker().remove();
19053 validateValue : function(value)
19055 if(value.length < 1) {
19056 if(this.allowBlank){
19062 if(value.length < this.minLength){
19065 if(value.length > this.maxLength){
19069 var vt = Roo.form.VTypes;
19070 if(!vt[this.vtype](value, this)){
19074 if(typeof this.validator == "function"){
19075 var msg = this.validator(value);
19081 if(this.regex && !this.regex.test(value)){
19085 if(typeof(this.parseDate(value)) == 'undefined'){
19089 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19093 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19103 Roo.apply(Roo.bootstrap.DateField, {
19114 html: '<i class="fa fa-arrow-left"/>'
19124 html: '<i class="fa fa-arrow-right"/>'
19166 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19167 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19168 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19169 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19170 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19183 navFnc: 'FullYear',
19188 navFnc: 'FullYear',
19193 Roo.apply(Roo.bootstrap.DateField, {
19197 cls: 'datepicker dropdown-menu roo-dynamic',
19201 cls: 'datepicker-days',
19205 cls: 'table-condensed',
19207 Roo.bootstrap.DateField.head,
19211 Roo.bootstrap.DateField.footer
19218 cls: 'datepicker-months',
19222 cls: 'table-condensed',
19224 Roo.bootstrap.DateField.head,
19225 Roo.bootstrap.DateField.content,
19226 Roo.bootstrap.DateField.footer
19233 cls: 'datepicker-years',
19237 cls: 'table-condensed',
19239 Roo.bootstrap.DateField.head,
19240 Roo.bootstrap.DateField.content,
19241 Roo.bootstrap.DateField.footer
19260 * @class Roo.bootstrap.TimeField
19261 * @extends Roo.bootstrap.Input
19262 * Bootstrap DateField class
19266 * Create a new TimeField
19267 * @param {Object} config The config object
19270 Roo.bootstrap.TimeField = function(config){
19271 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19275 * Fires when this field show.
19276 * @param {Roo.bootstrap.DateField} thisthis
19277 * @param {Mixed} date The date value
19282 * Fires when this field hide.
19283 * @param {Roo.bootstrap.DateField} this
19284 * @param {Mixed} date The date value
19289 * Fires when select a date.
19290 * @param {Roo.bootstrap.DateField} this
19291 * @param {Mixed} date The date value
19297 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19300 * @cfg {String} format
19301 * The default time format string which can be overriden for localization support. The format must be
19302 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19306 onRender: function(ct, position)
19309 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19311 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19313 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19315 this.pop = this.picker().select('>.datepicker-time',true).first();
19316 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19318 this.picker().on('mousedown', this.onMousedown, this);
19319 this.picker().on('click', this.onClick, this);
19321 this.picker().addClass('datepicker-dropdown');
19326 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19327 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19328 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19329 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19330 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19331 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19335 fireKey: function(e){
19336 if (!this.picker().isVisible()){
19337 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19343 e.preventDefault();
19351 this.onTogglePeriod();
19354 this.onIncrementMinutes();
19357 this.onDecrementMinutes();
19366 onClick: function(e) {
19367 e.stopPropagation();
19368 e.preventDefault();
19371 picker : function()
19373 return this.el.select('.datepicker', true).first();
19376 fillTime: function()
19378 var time = this.pop.select('tbody', true).first();
19380 time.dom.innerHTML = '';
19395 cls: 'hours-up glyphicon glyphicon-chevron-up'
19415 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19436 cls: 'timepicker-hour',
19451 cls: 'timepicker-minute',
19466 cls: 'btn btn-primary period',
19488 cls: 'hours-down glyphicon glyphicon-chevron-down'
19508 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19526 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19533 var hours = this.time.getHours();
19534 var minutes = this.time.getMinutes();
19547 hours = hours - 12;
19551 hours = '0' + hours;
19555 minutes = '0' + minutes;
19558 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19559 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19560 this.pop.select('button', true).first().dom.innerHTML = period;
19566 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19568 var cls = ['bottom'];
19570 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19577 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19582 this.picker().addClass(cls.join('-'));
19586 Roo.each(cls, function(c){
19588 _this.picker().setTop(_this.inputEl().getHeight());
19592 _this.picker().setTop(0 - _this.picker().getHeight());
19597 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19601 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19608 onFocus : function()
19610 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19614 onBlur : function()
19616 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19622 this.picker().show();
19627 this.fireEvent('show', this, this.date);
19632 this.picker().hide();
19635 this.fireEvent('hide', this, this.date);
19638 setTime : function()
19641 this.setValue(this.time.format(this.format));
19643 this.fireEvent('select', this, this.date);
19648 onMousedown: function(e){
19649 e.stopPropagation();
19650 e.preventDefault();
19653 onIncrementHours: function()
19655 Roo.log('onIncrementHours');
19656 this.time = this.time.add(Date.HOUR, 1);
19661 onDecrementHours: function()
19663 Roo.log('onDecrementHours');
19664 this.time = this.time.add(Date.HOUR, -1);
19668 onIncrementMinutes: function()
19670 Roo.log('onIncrementMinutes');
19671 this.time = this.time.add(Date.MINUTE, 1);
19675 onDecrementMinutes: function()
19677 Roo.log('onDecrementMinutes');
19678 this.time = this.time.add(Date.MINUTE, -1);
19682 onTogglePeriod: function()
19684 Roo.log('onTogglePeriod');
19685 this.time = this.time.add(Date.HOUR, 12);
19692 Roo.apply(Roo.bootstrap.TimeField, {
19722 cls: 'btn btn-info ok',
19734 Roo.apply(Roo.bootstrap.TimeField, {
19738 cls: 'datepicker dropdown-menu',
19742 cls: 'datepicker-time',
19746 cls: 'table-condensed',
19748 Roo.bootstrap.TimeField.content,
19749 Roo.bootstrap.TimeField.footer
19768 * @class Roo.bootstrap.MonthField
19769 * @extends Roo.bootstrap.Input
19770 * Bootstrap MonthField class
19772 * @cfg {String} language default en
19775 * Create a new MonthField
19776 * @param {Object} config The config object
19779 Roo.bootstrap.MonthField = function(config){
19780 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19785 * Fires when this field show.
19786 * @param {Roo.bootstrap.MonthField} this
19787 * @param {Mixed} date The date value
19792 * Fires when this field hide.
19793 * @param {Roo.bootstrap.MonthField} this
19794 * @param {Mixed} date The date value
19799 * Fires when select a date.
19800 * @param {Roo.bootstrap.MonthField} this
19801 * @param {String} oldvalue The old value
19802 * @param {String} newvalue The new value
19808 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19810 onRender: function(ct, position)
19813 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19815 this.language = this.language || 'en';
19816 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19817 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19819 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19820 this.isInline = false;
19821 this.isInput = true;
19822 this.component = this.el.select('.add-on', true).first() || false;
19823 this.component = (this.component && this.component.length === 0) ? false : this.component;
19824 this.hasInput = this.component && this.inputEL().length;
19826 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19828 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19830 this.picker().on('mousedown', this.onMousedown, this);
19831 this.picker().on('click', this.onClick, this);
19833 this.picker().addClass('datepicker-dropdown');
19835 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19836 v.setStyle('width', '189px');
19843 if(this.isInline) {
19849 setValue: function(v, suppressEvent)
19851 var o = this.getValue();
19853 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19857 if(suppressEvent !== true){
19858 this.fireEvent('select', this, o, v);
19863 getValue: function()
19868 onClick: function(e)
19870 e.stopPropagation();
19871 e.preventDefault();
19873 var target = e.getTarget();
19875 if(target.nodeName.toLowerCase() === 'i'){
19876 target = Roo.get(target).dom.parentNode;
19879 var nodeName = target.nodeName;
19880 var className = target.className;
19881 var html = target.innerHTML;
19883 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19887 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19889 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19895 picker : function()
19897 return this.pickerEl;
19900 fillMonths: function()
19903 var months = this.picker().select('>.datepicker-months td', true).first();
19905 months.dom.innerHTML = '';
19911 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19914 months.createChild(month);
19923 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19924 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19927 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19928 e.removeClass('active');
19930 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19931 e.addClass('active');
19938 if(this.isInline) {
19942 this.picker().removeClass(['bottom', 'top']);
19944 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19946 * place to the top of element!
19950 this.picker().addClass('top');
19951 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19956 this.picker().addClass('bottom');
19958 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19961 onFocus : function()
19963 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19967 onBlur : function()
19969 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19971 var d = this.inputEl().getValue();
19980 this.picker().show();
19981 this.picker().select('>.datepicker-months', true).first().show();
19985 this.fireEvent('show', this, this.date);
19990 if(this.isInline) {
19993 this.picker().hide();
19994 this.fireEvent('hide', this, this.date);
19998 onMousedown: function(e)
20000 e.stopPropagation();
20001 e.preventDefault();
20006 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20010 fireKey: function(e)
20012 if (!this.picker().isVisible()){
20013 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20024 e.preventDefault();
20028 dir = e.keyCode == 37 ? -1 : 1;
20030 this.vIndex = this.vIndex + dir;
20032 if(this.vIndex < 0){
20036 if(this.vIndex > 11){
20040 if(isNaN(this.vIndex)){
20044 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20050 dir = e.keyCode == 38 ? -1 : 1;
20052 this.vIndex = this.vIndex + dir * 4;
20054 if(this.vIndex < 0){
20058 if(this.vIndex > 11){
20062 if(isNaN(this.vIndex)){
20066 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20071 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20072 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20076 e.preventDefault();
20079 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20080 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20096 this.picker().remove();
20101 Roo.apply(Roo.bootstrap.MonthField, {
20120 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20121 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20126 Roo.apply(Roo.bootstrap.MonthField, {
20130 cls: 'datepicker dropdown-menu roo-dynamic',
20134 cls: 'datepicker-months',
20138 cls: 'table-condensed',
20140 Roo.bootstrap.DateField.content
20160 * @class Roo.bootstrap.CheckBox
20161 * @extends Roo.bootstrap.Input
20162 * Bootstrap CheckBox class
20164 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20165 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20166 * @cfg {String} boxLabel The text that appears beside the checkbox
20167 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20168 * @cfg {Boolean} checked initnal the element
20169 * @cfg {Boolean} inline inline the element (default false)
20170 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20171 * @cfg {String} tooltip label tooltip
20174 * Create a new CheckBox
20175 * @param {Object} config The config object
20178 Roo.bootstrap.CheckBox = function(config){
20179 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20184 * Fires when the element is checked or unchecked.
20185 * @param {Roo.bootstrap.CheckBox} this This input
20186 * @param {Boolean} checked The new checked value
20191 * Fires when the element is click.
20192 * @param {Roo.bootstrap.CheckBox} this This input
20199 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20201 inputType: 'checkbox',
20210 getAutoCreate : function()
20212 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20218 cfg.cls = 'form-group ' + this.inputType; //input-group
20221 cfg.cls += ' ' + this.inputType + '-inline';
20227 type : this.inputType,
20228 value : this.inputValue,
20229 cls : 'roo-' + this.inputType, //'form-box',
20230 placeholder : this.placeholder || ''
20234 if(this.inputType != 'radio'){
20238 cls : 'roo-hidden-value',
20239 value : this.checked ? this.inputValue : this.valueOff
20244 if (this.weight) { // Validity check?
20245 cfg.cls += " " + this.inputType + "-" + this.weight;
20248 if (this.disabled) {
20249 input.disabled=true;
20253 input.checked = this.checked;
20258 input.name = this.name;
20260 if(this.inputType != 'radio'){
20261 hidden.name = this.name;
20262 input.name = '_hidden_' + this.name;
20267 input.cls += ' input-' + this.size;
20272 ['xs','sm','md','lg'].map(function(size){
20273 if (settings[size]) {
20274 cfg.cls += ' col-' + size + '-' + settings[size];
20278 var inputblock = input;
20280 if (this.before || this.after) {
20283 cls : 'input-group',
20288 inputblock.cn.push({
20290 cls : 'input-group-addon',
20295 inputblock.cn.push(input);
20297 if(this.inputType != 'radio'){
20298 inputblock.cn.push(hidden);
20302 inputblock.cn.push({
20304 cls : 'input-group-addon',
20311 if (align ==='left' && this.fieldLabel.length) {
20312 // Roo.log("left and has label");
20317 cls : 'control-label',
20318 html : this.fieldLabel
20328 if(this.labelWidth > 12){
20329 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20332 if(this.labelWidth < 13 && this.labelmd == 0){
20333 this.labelmd = this.labelWidth;
20336 if(this.labellg > 0){
20337 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20338 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20341 if(this.labelmd > 0){
20342 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20343 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20346 if(this.labelsm > 0){
20347 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20348 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20351 if(this.labelxs > 0){
20352 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20353 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20356 } else if ( this.fieldLabel.length) {
20357 // Roo.log(" label");
20361 tag: this.boxLabel ? 'span' : 'label',
20363 cls: 'control-label box-input-label',
20364 //cls : 'input-group-addon',
20365 html : this.fieldLabel
20374 // Roo.log(" no label && no align");
20375 cfg.cn = [ inputblock ] ;
20381 var boxLabelCfg = {
20383 //'for': id, // box label is handled by onclick - so no for...
20385 html: this.boxLabel
20389 boxLabelCfg.tooltip = this.tooltip;
20392 cfg.cn.push(boxLabelCfg);
20395 if(this.inputType != 'radio'){
20396 cfg.cn.push(hidden);
20404 * return the real input element.
20406 inputEl: function ()
20408 return this.el.select('input.roo-' + this.inputType,true).first();
20410 hiddenEl: function ()
20412 return this.el.select('input.roo-hidden-value',true).first();
20415 labelEl: function()
20417 return this.el.select('label.control-label',true).first();
20419 /* depricated... */
20423 return this.labelEl();
20426 boxLabelEl: function()
20428 return this.el.select('label.box-label',true).first();
20431 initEvents : function()
20433 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20435 this.inputEl().on('click', this.onClick, this);
20437 if (this.boxLabel) {
20438 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20441 this.startValue = this.getValue();
20444 Roo.bootstrap.CheckBox.register(this);
20448 onClick : function(e)
20450 if(this.fireEvent('click', this, e) !== false){
20451 this.setChecked(!this.checked);
20456 setChecked : function(state,suppressEvent)
20458 this.startValue = this.getValue();
20460 if(this.inputType == 'radio'){
20462 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20463 e.dom.checked = false;
20466 this.inputEl().dom.checked = true;
20468 this.inputEl().dom.value = this.inputValue;
20470 if(suppressEvent !== true){
20471 this.fireEvent('check', this, true);
20479 this.checked = state;
20481 this.inputEl().dom.checked = state;
20484 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20486 if(suppressEvent !== true){
20487 this.fireEvent('check', this, state);
20493 getValue : function()
20495 if(this.inputType == 'radio'){
20496 return this.getGroupValue();
20499 return this.hiddenEl().dom.value;
20503 getGroupValue : function()
20505 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20509 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20512 setValue : function(v,suppressEvent)
20514 if(this.inputType == 'radio'){
20515 this.setGroupValue(v, suppressEvent);
20519 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20524 setGroupValue : function(v, suppressEvent)
20526 this.startValue = this.getValue();
20528 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20529 e.dom.checked = false;
20531 if(e.dom.value == v){
20532 e.dom.checked = true;
20536 if(suppressEvent !== true){
20537 this.fireEvent('check', this, true);
20545 validate : function()
20549 (this.inputType == 'radio' && this.validateRadio()) ||
20550 (this.inputType == 'checkbox' && this.validateCheckbox())
20556 this.markInvalid();
20560 validateRadio : function()
20562 if(this.allowBlank){
20568 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20569 if(!e.dom.checked){
20581 validateCheckbox : function()
20584 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20585 //return (this.getValue() == this.inputValue) ? true : false;
20588 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20596 for(var i in group){
20597 if(group[i].el.isVisible(true)){
20605 for(var i in group){
20610 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20617 * Mark this field as valid
20619 markValid : function()
20623 this.fireEvent('valid', this);
20625 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20628 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20635 if(this.inputType == 'radio'){
20636 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20637 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20638 e.findParent('.form-group', false, true).addClass(_this.validClass);
20645 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20646 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20650 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20656 for(var i in group){
20657 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20658 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20663 * Mark this field as invalid
20664 * @param {String} msg The validation message
20666 markInvalid : function(msg)
20668 if(this.allowBlank){
20674 this.fireEvent('invalid', this, msg);
20676 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20679 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20683 label.markInvalid();
20686 if(this.inputType == 'radio'){
20687 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20688 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20689 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20696 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20697 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20701 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20707 for(var i in group){
20708 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20709 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20714 clearInvalid : function()
20716 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20718 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20720 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20722 if (label && label.iconEl) {
20723 label.iconEl.removeClass(label.validClass);
20724 label.iconEl.removeClass(label.invalidClass);
20728 disable : function()
20730 if(this.inputType != 'radio'){
20731 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20738 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20739 _this.getActionEl().addClass(this.disabledClass);
20740 e.dom.disabled = true;
20744 this.disabled = true;
20745 this.fireEvent("disable", this);
20749 enable : function()
20751 if(this.inputType != 'radio'){
20752 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20759 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20760 _this.getActionEl().removeClass(this.disabledClass);
20761 e.dom.disabled = false;
20765 this.disabled = false;
20766 this.fireEvent("enable", this);
20770 setBoxLabel : function(v)
20775 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20781 Roo.apply(Roo.bootstrap.CheckBox, {
20786 * register a CheckBox Group
20787 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20789 register : function(checkbox)
20791 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20792 this.groups[checkbox.groupId] = {};
20795 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20799 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20803 * fetch a CheckBox Group based on the group ID
20804 * @param {string} the group ID
20805 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20807 get: function(groupId) {
20808 if (typeof(this.groups[groupId]) == 'undefined') {
20812 return this.groups[groupId] ;
20825 * @class Roo.bootstrap.Radio
20826 * @extends Roo.bootstrap.Component
20827 * Bootstrap Radio class
20828 * @cfg {String} boxLabel - the label associated
20829 * @cfg {String} value - the value of radio
20832 * Create a new Radio
20833 * @param {Object} config The config object
20835 Roo.bootstrap.Radio = function(config){
20836 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20840 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20846 getAutoCreate : function()
20850 cls : 'form-group radio',
20855 html : this.boxLabel
20863 initEvents : function()
20865 this.parent().register(this);
20867 this.el.on('click', this.onClick, this);
20871 onClick : function()
20873 this.setChecked(true);
20876 setChecked : function(state, suppressEvent)
20878 this.parent().setValue(this.value, suppressEvent);
20882 setBoxLabel : function(v)
20887 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20902 * @class Roo.bootstrap.SecurePass
20903 * @extends Roo.bootstrap.Input
20904 * Bootstrap SecurePass class
20908 * Create a new SecurePass
20909 * @param {Object} config The config object
20912 Roo.bootstrap.SecurePass = function (config) {
20913 // these go here, so the translation tool can replace them..
20915 PwdEmpty: "Please type a password, and then retype it to confirm.",
20916 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20917 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20918 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20919 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20920 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20921 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20922 TooWeak: "Your password is Too Weak."
20924 this.meterLabel = "Password strength:";
20925 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20926 this.meterClass = [
20927 "roo-password-meter-tooweak",
20928 "roo-password-meter-weak",
20929 "roo-password-meter-medium",
20930 "roo-password-meter-strong",
20931 "roo-password-meter-grey"
20936 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20939 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20941 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20943 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20944 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20945 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20946 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20947 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20948 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20949 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20959 * @cfg {String/Object} Label for the strength meter (defaults to
20960 * 'Password strength:')
20965 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20966 * ['Weak', 'Medium', 'Strong'])
20969 pwdStrengths: false,
20982 initEvents: function ()
20984 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20986 if (this.el.is('input[type=password]') && Roo.isSafari) {
20987 this.el.on('keydown', this.SafariOnKeyDown, this);
20990 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20993 onRender: function (ct, position)
20995 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20996 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20997 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20999 this.trigger.createChild({
21004 cls: 'roo-password-meter-grey col-xs-12',
21007 //width: this.meterWidth + 'px'
21011 cls: 'roo-password-meter-text'
21017 if (this.hideTrigger) {
21018 this.trigger.setDisplayed(false);
21020 this.setSize(this.width || '', this.height || '');
21023 onDestroy: function ()
21025 if (this.trigger) {
21026 this.trigger.removeAllListeners();
21027 this.trigger.remove();
21030 this.wrap.remove();
21032 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21035 checkStrength: function ()
21037 var pwd = this.inputEl().getValue();
21038 if (pwd == this._lastPwd) {
21043 if (this.ClientSideStrongPassword(pwd)) {
21045 } else if (this.ClientSideMediumPassword(pwd)) {
21047 } else if (this.ClientSideWeakPassword(pwd)) {
21053 Roo.log('strength1: ' + strength);
21055 //var pm = this.trigger.child('div/div/div').dom;
21056 var pm = this.trigger.child('div/div');
21057 pm.removeClass(this.meterClass);
21058 pm.addClass(this.meterClass[strength]);
21061 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21063 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21065 this._lastPwd = pwd;
21069 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21071 this._lastPwd = '';
21073 var pm = this.trigger.child('div/div');
21074 pm.removeClass(this.meterClass);
21075 pm.addClass('roo-password-meter-grey');
21078 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21081 this.inputEl().dom.type='password';
21084 validateValue: function (value)
21087 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21090 if (value.length == 0) {
21091 if (this.allowBlank) {
21092 this.clearInvalid();
21096 this.markInvalid(this.errors.PwdEmpty);
21097 this.errorMsg = this.errors.PwdEmpty;
21105 if ('[\x21-\x7e]*'.match(value)) {
21106 this.markInvalid(this.errors.PwdBadChar);
21107 this.errorMsg = this.errors.PwdBadChar;
21110 if (value.length < 6) {
21111 this.markInvalid(this.errors.PwdShort);
21112 this.errorMsg = this.errors.PwdShort;
21115 if (value.length > 16) {
21116 this.markInvalid(this.errors.PwdLong);
21117 this.errorMsg = this.errors.PwdLong;
21121 if (this.ClientSideStrongPassword(value)) {
21123 } else if (this.ClientSideMediumPassword(value)) {
21125 } else if (this.ClientSideWeakPassword(value)) {
21132 if (strength < 2) {
21133 //this.markInvalid(this.errors.TooWeak);
21134 this.errorMsg = this.errors.TooWeak;
21139 console.log('strength2: ' + strength);
21141 //var pm = this.trigger.child('div/div/div').dom;
21143 var pm = this.trigger.child('div/div');
21144 pm.removeClass(this.meterClass);
21145 pm.addClass(this.meterClass[strength]);
21147 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21149 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21151 this.errorMsg = '';
21155 CharacterSetChecks: function (type)
21158 this.fResult = false;
21161 isctype: function (character, type)
21164 case this.kCapitalLetter:
21165 if (character >= 'A' && character <= 'Z') {
21170 case this.kSmallLetter:
21171 if (character >= 'a' && character <= 'z') {
21177 if (character >= '0' && character <= '9') {
21182 case this.kPunctuation:
21183 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21194 IsLongEnough: function (pwd, size)
21196 return !(pwd == null || isNaN(size) || pwd.length < size);
21199 SpansEnoughCharacterSets: function (word, nb)
21201 if (!this.IsLongEnough(word, nb))
21206 var characterSetChecks = new Array(
21207 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21208 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21211 for (var index = 0; index < word.length; ++index) {
21212 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21213 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21214 characterSetChecks[nCharSet].fResult = true;
21221 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21222 if (characterSetChecks[nCharSet].fResult) {
21227 if (nCharSets < nb) {
21233 ClientSideStrongPassword: function (pwd)
21235 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21238 ClientSideMediumPassword: function (pwd)
21240 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21243 ClientSideWeakPassword: function (pwd)
21245 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21248 })//<script type="text/javascript">
21251 * Based Ext JS Library 1.1.1
21252 * Copyright(c) 2006-2007, Ext JS, LLC.
21258 * @class Roo.HtmlEditorCore
21259 * @extends Roo.Component
21260 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21262 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21265 Roo.HtmlEditorCore = function(config){
21268 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21273 * @event initialize
21274 * Fires when the editor is fully initialized (including the iframe)
21275 * @param {Roo.HtmlEditorCore} this
21280 * Fires when the editor is first receives the focus. Any insertion must wait
21281 * until after this event.
21282 * @param {Roo.HtmlEditorCore} this
21286 * @event beforesync
21287 * Fires before the textarea is updated with content from the editor iframe. Return false
21288 * to cancel the sync.
21289 * @param {Roo.HtmlEditorCore} this
21290 * @param {String} html
21294 * @event beforepush
21295 * Fires before the iframe editor is updated with content from the textarea. Return false
21296 * to cancel the push.
21297 * @param {Roo.HtmlEditorCore} this
21298 * @param {String} html
21303 * Fires when the textarea is updated with content from the editor iframe.
21304 * @param {Roo.HtmlEditorCore} this
21305 * @param {String} html
21310 * Fires when the iframe editor is updated with content from the textarea.
21311 * @param {Roo.HtmlEditorCore} this
21312 * @param {String} html
21317 * @event editorevent
21318 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21319 * @param {Roo.HtmlEditorCore} this
21325 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21327 // defaults : white / black...
21328 this.applyBlacklists();
21335 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21339 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21345 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21350 * @cfg {Number} height (in pixels)
21354 * @cfg {Number} width (in pixels)
21359 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21362 stylesheets: false,
21367 // private properties
21368 validationEvent : false,
21370 initialized : false,
21372 sourceEditMode : false,
21373 onFocus : Roo.emptyFn,
21375 hideMode:'offsets',
21379 // blacklist + whitelisted elements..
21386 * Protected method that will not generally be called directly. It
21387 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21388 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21390 getDocMarkup : function(){
21394 // inherit styels from page...??
21395 if (this.stylesheets === false) {
21397 Roo.get(document.head).select('style').each(function(node) {
21398 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21401 Roo.get(document.head).select('link').each(function(node) {
21402 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21405 } else if (!this.stylesheets.length) {
21407 st = '<style type="text/css">' +
21408 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21411 st = '<style type="text/css">' +
21416 st += '<style type="text/css">' +
21417 'IMG { cursor: pointer } ' +
21420 var cls = 'roo-htmleditor-body';
21422 if(this.bodyCls.length){
21423 cls += ' ' + this.bodyCls;
21426 return '<html><head>' + st +
21427 //<style type="text/css">' +
21428 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21430 ' </head><body class="' + cls + '"></body></html>';
21434 onRender : function(ct, position)
21437 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21438 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21441 this.el.dom.style.border = '0 none';
21442 this.el.dom.setAttribute('tabIndex', -1);
21443 this.el.addClass('x-hidden hide');
21447 if(Roo.isIE){ // fix IE 1px bogus margin
21448 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21452 this.frameId = Roo.id();
21456 var iframe = this.owner.wrap.createChild({
21458 cls: 'form-control', // bootstrap..
21460 name: this.frameId,
21461 frameBorder : 'no',
21462 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21467 this.iframe = iframe.dom;
21469 this.assignDocWin();
21471 this.doc.designMode = 'on';
21474 this.doc.write(this.getDocMarkup());
21478 var task = { // must defer to wait for browser to be ready
21480 //console.log("run task?" + this.doc.readyState);
21481 this.assignDocWin();
21482 if(this.doc.body || this.doc.readyState == 'complete'){
21484 this.doc.designMode="on";
21488 Roo.TaskMgr.stop(task);
21489 this.initEditor.defer(10, this);
21496 Roo.TaskMgr.start(task);
21501 onResize : function(w, h)
21503 Roo.log('resize: ' +w + ',' + h );
21504 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21508 if(typeof w == 'number'){
21510 this.iframe.style.width = w + 'px';
21512 if(typeof h == 'number'){
21514 this.iframe.style.height = h + 'px';
21516 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21523 * Toggles the editor between standard and source edit mode.
21524 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21526 toggleSourceEdit : function(sourceEditMode){
21528 this.sourceEditMode = sourceEditMode === true;
21530 if(this.sourceEditMode){
21532 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21535 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21536 //this.iframe.className = '';
21539 //this.setSize(this.owner.wrap.getSize());
21540 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21547 * Protected method that will not generally be called directly. If you need/want
21548 * custom HTML cleanup, this is the method you should override.
21549 * @param {String} html The HTML to be cleaned
21550 * return {String} The cleaned HTML
21552 cleanHtml : function(html){
21553 html = String(html);
21554 if(html.length > 5){
21555 if(Roo.isSafari){ // strip safari nonsense
21556 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21559 if(html == ' '){
21566 * HTML Editor -> Textarea
21567 * Protected method that will not generally be called directly. Syncs the contents
21568 * of the editor iframe with the textarea.
21570 syncValue : function(){
21571 if(this.initialized){
21572 var bd = (this.doc.body || this.doc.documentElement);
21573 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21574 var html = bd.innerHTML;
21576 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21577 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21579 html = '<div style="'+m[0]+'">' + html + '</div>';
21582 html = this.cleanHtml(html);
21583 // fix up the special chars.. normaly like back quotes in word...
21584 // however we do not want to do this with chinese..
21585 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21586 var cc = b.charCodeAt();
21588 (cc >= 0x4E00 && cc < 0xA000 ) ||
21589 (cc >= 0x3400 && cc < 0x4E00 ) ||
21590 (cc >= 0xf900 && cc < 0xfb00 )
21596 if(this.owner.fireEvent('beforesync', this, html) !== false){
21597 this.el.dom.value = html;
21598 this.owner.fireEvent('sync', this, html);
21604 * Protected method that will not generally be called directly. Pushes the value of the textarea
21605 * into the iframe editor.
21607 pushValue : function(){
21608 if(this.initialized){
21609 var v = this.el.dom.value.trim();
21611 // if(v.length < 1){
21615 if(this.owner.fireEvent('beforepush', this, v) !== false){
21616 var d = (this.doc.body || this.doc.documentElement);
21618 this.cleanUpPaste();
21619 this.el.dom.value = d.innerHTML;
21620 this.owner.fireEvent('push', this, v);
21626 deferFocus : function(){
21627 this.focus.defer(10, this);
21631 focus : function(){
21632 if(this.win && !this.sourceEditMode){
21639 assignDocWin: function()
21641 var iframe = this.iframe;
21644 this.doc = iframe.contentWindow.document;
21645 this.win = iframe.contentWindow;
21647 // if (!Roo.get(this.frameId)) {
21650 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21651 // this.win = Roo.get(this.frameId).dom.contentWindow;
21653 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21657 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21658 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21663 initEditor : function(){
21664 //console.log("INIT EDITOR");
21665 this.assignDocWin();
21669 this.doc.designMode="on";
21671 this.doc.write(this.getDocMarkup());
21674 var dbody = (this.doc.body || this.doc.documentElement);
21675 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21676 // this copies styles from the containing element into thsi one..
21677 // not sure why we need all of this..
21678 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21680 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21681 //ss['background-attachment'] = 'fixed'; // w3c
21682 dbody.bgProperties = 'fixed'; // ie
21683 //Roo.DomHelper.applyStyles(dbody, ss);
21684 Roo.EventManager.on(this.doc, {
21685 //'mousedown': this.onEditorEvent,
21686 'mouseup': this.onEditorEvent,
21687 'dblclick': this.onEditorEvent,
21688 'click': this.onEditorEvent,
21689 'keyup': this.onEditorEvent,
21694 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21696 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21697 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21699 this.initialized = true;
21701 this.owner.fireEvent('initialize', this);
21706 onDestroy : function(){
21712 //for (var i =0; i < this.toolbars.length;i++) {
21713 // // fixme - ask toolbars for heights?
21714 // this.toolbars[i].onDestroy();
21717 //this.wrap.dom.innerHTML = '';
21718 //this.wrap.remove();
21723 onFirstFocus : function(){
21725 this.assignDocWin();
21728 this.activated = true;
21731 if(Roo.isGecko){ // prevent silly gecko errors
21733 var s = this.win.getSelection();
21734 if(!s.focusNode || s.focusNode.nodeType != 3){
21735 var r = s.getRangeAt(0);
21736 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21741 this.execCmd('useCSS', true);
21742 this.execCmd('styleWithCSS', false);
21745 this.owner.fireEvent('activate', this);
21749 adjustFont: function(btn){
21750 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21751 //if(Roo.isSafari){ // safari
21754 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21755 if(Roo.isSafari){ // safari
21756 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21757 v = (v < 10) ? 10 : v;
21758 v = (v > 48) ? 48 : v;
21759 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21764 v = Math.max(1, v+adjust);
21766 this.execCmd('FontSize', v );
21769 onEditorEvent : function(e)
21771 this.owner.fireEvent('editorevent', this, e);
21772 // this.updateToolbar();
21773 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21776 insertTag : function(tg)
21778 // could be a bit smarter... -> wrap the current selected tRoo..
21779 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21781 range = this.createRange(this.getSelection());
21782 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21783 wrappingNode.appendChild(range.extractContents());
21784 range.insertNode(wrappingNode);
21791 this.execCmd("formatblock", tg);
21795 insertText : function(txt)
21799 var range = this.createRange();
21800 range.deleteContents();
21801 //alert(Sender.getAttribute('label'));
21803 range.insertNode(this.doc.createTextNode(txt));
21809 * Executes a Midas editor command on the editor document and performs necessary focus and
21810 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21811 * @param {String} cmd The Midas command
21812 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21814 relayCmd : function(cmd, value){
21816 this.execCmd(cmd, value);
21817 this.owner.fireEvent('editorevent', this);
21818 //this.updateToolbar();
21819 this.owner.deferFocus();
21823 * Executes a Midas editor command directly on the editor document.
21824 * For visual commands, you should use {@link #relayCmd} instead.
21825 * <b>This should only be called after the editor is initialized.</b>
21826 * @param {String} cmd The Midas command
21827 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21829 execCmd : function(cmd, value){
21830 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21837 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21839 * @param {String} text | dom node..
21841 insertAtCursor : function(text)
21844 if(!this.activated){
21850 var r = this.doc.selection.createRange();
21861 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21865 // from jquery ui (MIT licenced)
21867 var win = this.win;
21869 if (win.getSelection && win.getSelection().getRangeAt) {
21870 range = win.getSelection().getRangeAt(0);
21871 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21872 range.insertNode(node);
21873 } else if (win.document.selection && win.document.selection.createRange) {
21874 // no firefox support
21875 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21876 win.document.selection.createRange().pasteHTML(txt);
21878 // no firefox support
21879 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21880 this.execCmd('InsertHTML', txt);
21889 mozKeyPress : function(e){
21891 var c = e.getCharCode(), cmd;
21894 c = String.fromCharCode(c).toLowerCase();
21908 this.cleanUpPaste.defer(100, this);
21916 e.preventDefault();
21924 fixKeys : function(){ // load time branching for fastest keydown performance
21926 return function(e){
21927 var k = e.getKey(), r;
21930 r = this.doc.selection.createRange();
21933 r.pasteHTML('    ');
21940 r = this.doc.selection.createRange();
21942 var target = r.parentElement();
21943 if(!target || target.tagName.toLowerCase() != 'li'){
21945 r.pasteHTML('<br />');
21951 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21952 this.cleanUpPaste.defer(100, this);
21958 }else if(Roo.isOpera){
21959 return function(e){
21960 var k = e.getKey();
21964 this.execCmd('InsertHTML','    ');
21967 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21968 this.cleanUpPaste.defer(100, this);
21973 }else if(Roo.isSafari){
21974 return function(e){
21975 var k = e.getKey();
21979 this.execCmd('InsertText','\t');
21983 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21984 this.cleanUpPaste.defer(100, this);
21992 getAllAncestors: function()
21994 var p = this.getSelectedNode();
21997 a.push(p); // push blank onto stack..
21998 p = this.getParentElement();
22002 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22006 a.push(this.doc.body);
22010 lastSelNode : false,
22013 getSelection : function()
22015 this.assignDocWin();
22016 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22019 getSelectedNode: function()
22021 // this may only work on Gecko!!!
22023 // should we cache this!!!!
22028 var range = this.createRange(this.getSelection()).cloneRange();
22031 var parent = range.parentElement();
22033 var testRange = range.duplicate();
22034 testRange.moveToElementText(parent);
22035 if (testRange.inRange(range)) {
22038 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22041 parent = parent.parentElement;
22046 // is ancestor a text element.
22047 var ac = range.commonAncestorContainer;
22048 if (ac.nodeType == 3) {
22049 ac = ac.parentNode;
22052 var ar = ac.childNodes;
22055 var other_nodes = [];
22056 var has_other_nodes = false;
22057 for (var i=0;i<ar.length;i++) {
22058 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22061 // fullly contained node.
22063 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22068 // probably selected..
22069 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22070 other_nodes.push(ar[i]);
22074 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22079 has_other_nodes = true;
22081 if (!nodes.length && other_nodes.length) {
22082 nodes= other_nodes;
22084 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22090 createRange: function(sel)
22092 // this has strange effects when using with
22093 // top toolbar - not sure if it's a great idea.
22094 //this.editor.contentWindow.focus();
22095 if (typeof sel != "undefined") {
22097 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22099 return this.doc.createRange();
22102 return this.doc.createRange();
22105 getParentElement: function()
22108 this.assignDocWin();
22109 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22111 var range = this.createRange(sel);
22114 var p = range.commonAncestorContainer;
22115 while (p.nodeType == 3) { // text node
22126 * Range intersection.. the hard stuff...
22130 * [ -- selected range --- ]
22134 * if end is before start or hits it. fail.
22135 * if start is after end or hits it fail.
22137 * if either hits (but other is outside. - then it's not
22143 // @see http://www.thismuchiknow.co.uk/?p=64.
22144 rangeIntersectsNode : function(range, node)
22146 var nodeRange = node.ownerDocument.createRange();
22148 nodeRange.selectNode(node);
22150 nodeRange.selectNodeContents(node);
22153 var rangeStartRange = range.cloneRange();
22154 rangeStartRange.collapse(true);
22156 var rangeEndRange = range.cloneRange();
22157 rangeEndRange.collapse(false);
22159 var nodeStartRange = nodeRange.cloneRange();
22160 nodeStartRange.collapse(true);
22162 var nodeEndRange = nodeRange.cloneRange();
22163 nodeEndRange.collapse(false);
22165 return rangeStartRange.compareBoundaryPoints(
22166 Range.START_TO_START, nodeEndRange) == -1 &&
22167 rangeEndRange.compareBoundaryPoints(
22168 Range.START_TO_START, nodeStartRange) == 1;
22172 rangeCompareNode : function(range, node)
22174 var nodeRange = node.ownerDocument.createRange();
22176 nodeRange.selectNode(node);
22178 nodeRange.selectNodeContents(node);
22182 range.collapse(true);
22184 nodeRange.collapse(true);
22186 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22187 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22189 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22191 var nodeIsBefore = ss == 1;
22192 var nodeIsAfter = ee == -1;
22194 if (nodeIsBefore && nodeIsAfter) {
22197 if (!nodeIsBefore && nodeIsAfter) {
22198 return 1; //right trailed.
22201 if (nodeIsBefore && !nodeIsAfter) {
22202 return 2; // left trailed.
22208 // private? - in a new class?
22209 cleanUpPaste : function()
22211 // cleans up the whole document..
22212 Roo.log('cleanuppaste');
22214 this.cleanUpChildren(this.doc.body);
22215 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22216 if (clean != this.doc.body.innerHTML) {
22217 this.doc.body.innerHTML = clean;
22222 cleanWordChars : function(input) {// change the chars to hex code
22223 var he = Roo.HtmlEditorCore;
22225 var output = input;
22226 Roo.each(he.swapCodes, function(sw) {
22227 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22229 output = output.replace(swapper, sw[1]);
22236 cleanUpChildren : function (n)
22238 if (!n.childNodes.length) {
22241 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22242 this.cleanUpChild(n.childNodes[i]);
22249 cleanUpChild : function (node)
22252 //console.log(node);
22253 if (node.nodeName == "#text") {
22254 // clean up silly Windows -- stuff?
22257 if (node.nodeName == "#comment") {
22258 node.parentNode.removeChild(node);
22259 // clean up silly Windows -- stuff?
22262 var lcname = node.tagName.toLowerCase();
22263 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22264 // whitelist of tags..
22266 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22268 node.parentNode.removeChild(node);
22273 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22275 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22276 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22278 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22279 // remove_keep_children = true;
22282 if (remove_keep_children) {
22283 this.cleanUpChildren(node);
22284 // inserts everything just before this node...
22285 while (node.childNodes.length) {
22286 var cn = node.childNodes[0];
22287 node.removeChild(cn);
22288 node.parentNode.insertBefore(cn, node);
22290 node.parentNode.removeChild(node);
22294 if (!node.attributes || !node.attributes.length) {
22295 this.cleanUpChildren(node);
22299 function cleanAttr(n,v)
22302 if (v.match(/^\./) || v.match(/^\//)) {
22305 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22308 if (v.match(/^#/)) {
22311 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22312 node.removeAttribute(n);
22316 var cwhite = this.cwhite;
22317 var cblack = this.cblack;
22319 function cleanStyle(n,v)
22321 if (v.match(/expression/)) { //XSS?? should we even bother..
22322 node.removeAttribute(n);
22326 var parts = v.split(/;/);
22329 Roo.each(parts, function(p) {
22330 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22334 var l = p.split(':').shift().replace(/\s+/g,'');
22335 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22337 if ( cwhite.length && cblack.indexOf(l) > -1) {
22338 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22339 //node.removeAttribute(n);
22343 // only allow 'c whitelisted system attributes'
22344 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22345 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22346 //node.removeAttribute(n);
22356 if (clean.length) {
22357 node.setAttribute(n, clean.join(';'));
22359 node.removeAttribute(n);
22365 for (var i = node.attributes.length-1; i > -1 ; i--) {
22366 var a = node.attributes[i];
22369 if (a.name.toLowerCase().substr(0,2)=='on') {
22370 node.removeAttribute(a.name);
22373 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22374 node.removeAttribute(a.name);
22377 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22378 cleanAttr(a.name,a.value); // fixme..
22381 if (a.name == 'style') {
22382 cleanStyle(a.name,a.value);
22385 /// clean up MS crap..
22386 // tecnically this should be a list of valid class'es..
22389 if (a.name == 'class') {
22390 if (a.value.match(/^Mso/)) {
22391 node.className = '';
22394 if (a.value.match(/^body$/)) {
22395 node.className = '';
22406 this.cleanUpChildren(node);
22412 * Clean up MS wordisms...
22414 cleanWord : function(node)
22419 this.cleanWord(this.doc.body);
22422 if (node.nodeName == "#text") {
22423 // clean up silly Windows -- stuff?
22426 if (node.nodeName == "#comment") {
22427 node.parentNode.removeChild(node);
22428 // clean up silly Windows -- stuff?
22432 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22433 node.parentNode.removeChild(node);
22437 // remove - but keep children..
22438 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22439 while (node.childNodes.length) {
22440 var cn = node.childNodes[0];
22441 node.removeChild(cn);
22442 node.parentNode.insertBefore(cn, node);
22444 node.parentNode.removeChild(node);
22445 this.iterateChildren(node, this.cleanWord);
22449 if (node.className.length) {
22451 var cn = node.className.split(/\W+/);
22453 Roo.each(cn, function(cls) {
22454 if (cls.match(/Mso[a-zA-Z]+/)) {
22459 node.className = cna.length ? cna.join(' ') : '';
22461 node.removeAttribute("class");
22465 if (node.hasAttribute("lang")) {
22466 node.removeAttribute("lang");
22469 if (node.hasAttribute("style")) {
22471 var styles = node.getAttribute("style").split(";");
22473 Roo.each(styles, function(s) {
22474 if (!s.match(/:/)) {
22477 var kv = s.split(":");
22478 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22481 // what ever is left... we allow.
22484 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22485 if (!nstyle.length) {
22486 node.removeAttribute('style');
22489 this.iterateChildren(node, this.cleanWord);
22495 * iterateChildren of a Node, calling fn each time, using this as the scole..
22496 * @param {DomNode} node node to iterate children of.
22497 * @param {Function} fn method of this class to call on each item.
22499 iterateChildren : function(node, fn)
22501 if (!node.childNodes.length) {
22504 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22505 fn.call(this, node.childNodes[i])
22511 * cleanTableWidths.
22513 * Quite often pasting from word etc.. results in tables with column and widths.
22514 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22517 cleanTableWidths : function(node)
22522 this.cleanTableWidths(this.doc.body);
22527 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22530 Roo.log(node.tagName);
22531 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22532 this.iterateChildren(node, this.cleanTableWidths);
22535 if (node.hasAttribute('width')) {
22536 node.removeAttribute('width');
22540 if (node.hasAttribute("style")) {
22543 var styles = node.getAttribute("style").split(";");
22545 Roo.each(styles, function(s) {
22546 if (!s.match(/:/)) {
22549 var kv = s.split(":");
22550 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22553 // what ever is left... we allow.
22556 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22557 if (!nstyle.length) {
22558 node.removeAttribute('style');
22562 this.iterateChildren(node, this.cleanTableWidths);
22570 domToHTML : function(currentElement, depth, nopadtext) {
22572 depth = depth || 0;
22573 nopadtext = nopadtext || false;
22575 if (!currentElement) {
22576 return this.domToHTML(this.doc.body);
22579 //Roo.log(currentElement);
22581 var allText = false;
22582 var nodeName = currentElement.nodeName;
22583 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22585 if (nodeName == '#text') {
22587 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22592 if (nodeName != 'BODY') {
22595 // Prints the node tagName, such as <A>, <IMG>, etc
22598 for(i = 0; i < currentElement.attributes.length;i++) {
22600 var aname = currentElement.attributes.item(i).name;
22601 if (!currentElement.attributes.item(i).value.length) {
22604 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22607 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22616 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22619 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22624 // Traverse the tree
22626 var currentElementChild = currentElement.childNodes.item(i);
22627 var allText = true;
22628 var innerHTML = '';
22630 while (currentElementChild) {
22631 // Formatting code (indent the tree so it looks nice on the screen)
22632 var nopad = nopadtext;
22633 if (lastnode == 'SPAN') {
22637 if (currentElementChild.nodeName == '#text') {
22638 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22639 toadd = nopadtext ? toadd : toadd.trim();
22640 if (!nopad && toadd.length > 80) {
22641 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22643 innerHTML += toadd;
22646 currentElementChild = currentElement.childNodes.item(i);
22652 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22654 // Recursively traverse the tree structure of the child node
22655 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22656 lastnode = currentElementChild.nodeName;
22658 currentElementChild=currentElement.childNodes.item(i);
22664 // The remaining code is mostly for formatting the tree
22665 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22670 ret+= "</"+tagName+">";
22676 applyBlacklists : function()
22678 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22679 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22683 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22684 if (b.indexOf(tag) > -1) {
22687 this.white.push(tag);
22691 Roo.each(w, function(tag) {
22692 if (b.indexOf(tag) > -1) {
22695 if (this.white.indexOf(tag) > -1) {
22698 this.white.push(tag);
22703 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22704 if (w.indexOf(tag) > -1) {
22707 this.black.push(tag);
22711 Roo.each(b, function(tag) {
22712 if (w.indexOf(tag) > -1) {
22715 if (this.black.indexOf(tag) > -1) {
22718 this.black.push(tag);
22723 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22724 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22728 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22729 if (b.indexOf(tag) > -1) {
22732 this.cwhite.push(tag);
22736 Roo.each(w, function(tag) {
22737 if (b.indexOf(tag) > -1) {
22740 if (this.cwhite.indexOf(tag) > -1) {
22743 this.cwhite.push(tag);
22748 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22749 if (w.indexOf(tag) > -1) {
22752 this.cblack.push(tag);
22756 Roo.each(b, function(tag) {
22757 if (w.indexOf(tag) > -1) {
22760 if (this.cblack.indexOf(tag) > -1) {
22763 this.cblack.push(tag);
22768 setStylesheets : function(stylesheets)
22770 if(typeof(stylesheets) == 'string'){
22771 Roo.get(this.iframe.contentDocument.head).createChild({
22773 rel : 'stylesheet',
22782 Roo.each(stylesheets, function(s) {
22787 Roo.get(_this.iframe.contentDocument.head).createChild({
22789 rel : 'stylesheet',
22798 removeStylesheets : function()
22802 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22807 setStyle : function(style)
22809 Roo.get(this.iframe.contentDocument.head).createChild({
22818 // hide stuff that is not compatible
22832 * @event specialkey
22836 * @cfg {String} fieldClass @hide
22839 * @cfg {String} focusClass @hide
22842 * @cfg {String} autoCreate @hide
22845 * @cfg {String} inputType @hide
22848 * @cfg {String} invalidClass @hide
22851 * @cfg {String} invalidText @hide
22854 * @cfg {String} msgFx @hide
22857 * @cfg {String} validateOnBlur @hide
22861 Roo.HtmlEditorCore.white = [
22862 'area', 'br', 'img', 'input', 'hr', 'wbr',
22864 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22865 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22866 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22867 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22868 'table', 'ul', 'xmp',
22870 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22873 'dir', 'menu', 'ol', 'ul', 'dl',
22879 Roo.HtmlEditorCore.black = [
22880 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22882 'base', 'basefont', 'bgsound', 'blink', 'body',
22883 'frame', 'frameset', 'head', 'html', 'ilayer',
22884 'iframe', 'layer', 'link', 'meta', 'object',
22885 'script', 'style' ,'title', 'xml' // clean later..
22887 Roo.HtmlEditorCore.clean = [
22888 'script', 'style', 'title', 'xml'
22890 Roo.HtmlEditorCore.remove = [
22895 Roo.HtmlEditorCore.ablack = [
22899 Roo.HtmlEditorCore.aclean = [
22900 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22904 Roo.HtmlEditorCore.pwhite= [
22905 'http', 'https', 'mailto'
22908 // white listed style attributes.
22909 Roo.HtmlEditorCore.cwhite= [
22910 // 'text-align', /// default is to allow most things..
22916 // black listed style attributes.
22917 Roo.HtmlEditorCore.cblack= [
22918 // 'font-size' -- this can be set by the project
22922 Roo.HtmlEditorCore.swapCodes =[
22941 * @class Roo.bootstrap.HtmlEditor
22942 * @extends Roo.bootstrap.TextArea
22943 * Bootstrap HtmlEditor class
22946 * Create a new HtmlEditor
22947 * @param {Object} config The config object
22950 Roo.bootstrap.HtmlEditor = function(config){
22951 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22952 if (!this.toolbars) {
22953 this.toolbars = [];
22956 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22959 * @event initialize
22960 * Fires when the editor is fully initialized (including the iframe)
22961 * @param {HtmlEditor} this
22966 * Fires when the editor is first receives the focus. Any insertion must wait
22967 * until after this event.
22968 * @param {HtmlEditor} this
22972 * @event beforesync
22973 * Fires before the textarea is updated with content from the editor iframe. Return false
22974 * to cancel the sync.
22975 * @param {HtmlEditor} this
22976 * @param {String} html
22980 * @event beforepush
22981 * Fires before the iframe editor is updated with content from the textarea. Return false
22982 * to cancel the push.
22983 * @param {HtmlEditor} this
22984 * @param {String} html
22989 * Fires when the textarea is updated with content from the editor iframe.
22990 * @param {HtmlEditor} this
22991 * @param {String} html
22996 * Fires when the iframe editor is updated with content from the textarea.
22997 * @param {HtmlEditor} this
22998 * @param {String} html
23002 * @event editmodechange
23003 * Fires when the editor switches edit modes
23004 * @param {HtmlEditor} this
23005 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23007 editmodechange: true,
23009 * @event editorevent
23010 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23011 * @param {HtmlEditor} this
23015 * @event firstfocus
23016 * Fires when on first focus - needed by toolbars..
23017 * @param {HtmlEditor} this
23022 * Auto save the htmlEditor value as a file into Events
23023 * @param {HtmlEditor} this
23027 * @event savedpreview
23028 * preview the saved version of htmlEditor
23029 * @param {HtmlEditor} this
23036 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23040 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23045 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23050 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23055 * @cfg {Number} height (in pixels)
23059 * @cfg {Number} width (in pixels)
23064 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23067 stylesheets: false,
23072 // private properties
23073 validationEvent : false,
23075 initialized : false,
23078 onFocus : Roo.emptyFn,
23080 hideMode:'offsets',
23082 tbContainer : false,
23086 toolbarContainer :function() {
23087 return this.wrap.select('.x-html-editor-tb',true).first();
23091 * Protected method that will not generally be called directly. It
23092 * is called when the editor creates its toolbar. Override this method if you need to
23093 * add custom toolbar buttons.
23094 * @param {HtmlEditor} editor
23096 createToolbar : function(){
23097 Roo.log('renewing');
23098 Roo.log("create toolbars");
23100 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23101 this.toolbars[0].render(this.toolbarContainer());
23105 // if (!editor.toolbars || !editor.toolbars.length) {
23106 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23109 // for (var i =0 ; i < editor.toolbars.length;i++) {
23110 // editor.toolbars[i] = Roo.factory(
23111 // typeof(editor.toolbars[i]) == 'string' ?
23112 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23113 // Roo.bootstrap.HtmlEditor);
23114 // editor.toolbars[i].init(editor);
23120 onRender : function(ct, position)
23122 // Roo.log("Call onRender: " + this.xtype);
23124 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23126 this.wrap = this.inputEl().wrap({
23127 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23130 this.editorcore.onRender(ct, position);
23132 if (this.resizable) {
23133 this.resizeEl = new Roo.Resizable(this.wrap, {
23137 minHeight : this.height,
23138 height: this.height,
23139 handles : this.resizable,
23142 resize : function(r, w, h) {
23143 _t.onResize(w,h); // -something
23149 this.createToolbar(this);
23152 if(!this.width && this.resizable){
23153 this.setSize(this.wrap.getSize());
23155 if (this.resizeEl) {
23156 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23157 // should trigger onReize..
23163 onResize : function(w, h)
23165 Roo.log('resize: ' +w + ',' + h );
23166 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23170 if(this.inputEl() ){
23171 if(typeof w == 'number'){
23172 var aw = w - this.wrap.getFrameWidth('lr');
23173 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23176 if(typeof h == 'number'){
23177 var tbh = -11; // fixme it needs to tool bar size!
23178 for (var i =0; i < this.toolbars.length;i++) {
23179 // fixme - ask toolbars for heights?
23180 tbh += this.toolbars[i].el.getHeight();
23181 //if (this.toolbars[i].footer) {
23182 // tbh += this.toolbars[i].footer.el.getHeight();
23190 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23191 ah -= 5; // knock a few pixes off for look..
23192 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23196 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23197 this.editorcore.onResize(ew,eh);
23202 * Toggles the editor between standard and source edit mode.
23203 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23205 toggleSourceEdit : function(sourceEditMode)
23207 this.editorcore.toggleSourceEdit(sourceEditMode);
23209 if(this.editorcore.sourceEditMode){
23210 Roo.log('editor - showing textarea');
23213 // Roo.log(this.syncValue());
23215 this.inputEl().removeClass(['hide', 'x-hidden']);
23216 this.inputEl().dom.removeAttribute('tabIndex');
23217 this.inputEl().focus();
23219 Roo.log('editor - hiding textarea');
23221 // Roo.log(this.pushValue());
23224 this.inputEl().addClass(['hide', 'x-hidden']);
23225 this.inputEl().dom.setAttribute('tabIndex', -1);
23226 //this.deferFocus();
23229 if(this.resizable){
23230 this.setSize(this.wrap.getSize());
23233 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23236 // private (for BoxComponent)
23237 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23239 // private (for BoxComponent)
23240 getResizeEl : function(){
23244 // private (for BoxComponent)
23245 getPositionEl : function(){
23250 initEvents : function(){
23251 this.originalValue = this.getValue();
23255 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23258 // markInvalid : Roo.emptyFn,
23260 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23263 // clearInvalid : Roo.emptyFn,
23265 setValue : function(v){
23266 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23267 this.editorcore.pushValue();
23272 deferFocus : function(){
23273 this.focus.defer(10, this);
23277 focus : function(){
23278 this.editorcore.focus();
23284 onDestroy : function(){
23290 for (var i =0; i < this.toolbars.length;i++) {
23291 // fixme - ask toolbars for heights?
23292 this.toolbars[i].onDestroy();
23295 this.wrap.dom.innerHTML = '';
23296 this.wrap.remove();
23301 onFirstFocus : function(){
23302 //Roo.log("onFirstFocus");
23303 this.editorcore.onFirstFocus();
23304 for (var i =0; i < this.toolbars.length;i++) {
23305 this.toolbars[i].onFirstFocus();
23311 syncValue : function()
23313 this.editorcore.syncValue();
23316 pushValue : function()
23318 this.editorcore.pushValue();
23322 // hide stuff that is not compatible
23336 * @event specialkey
23340 * @cfg {String} fieldClass @hide
23343 * @cfg {String} focusClass @hide
23346 * @cfg {String} autoCreate @hide
23349 * @cfg {String} inputType @hide
23352 * @cfg {String} invalidClass @hide
23355 * @cfg {String} invalidText @hide
23358 * @cfg {String} msgFx @hide
23361 * @cfg {String} validateOnBlur @hide
23370 Roo.namespace('Roo.bootstrap.htmleditor');
23372 * @class Roo.bootstrap.HtmlEditorToolbar1
23377 new Roo.bootstrap.HtmlEditor({
23380 new Roo.bootstrap.HtmlEditorToolbar1({
23381 disable : { fonts: 1 , format: 1, ..., ... , ...],
23387 * @cfg {Object} disable List of elements to disable..
23388 * @cfg {Array} btns List of additional buttons.
23392 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23395 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23398 Roo.apply(this, config);
23400 // default disabled, based on 'good practice'..
23401 this.disable = this.disable || {};
23402 Roo.applyIf(this.disable, {
23405 specialElements : true
23407 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23409 this.editor = config.editor;
23410 this.editorcore = config.editor.editorcore;
23412 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23414 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23415 // dont call parent... till later.
23417 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23422 editorcore : false,
23427 "h1","h2","h3","h4","h5","h6",
23429 "abbr", "acronym", "address", "cite", "samp", "var",
23433 onRender : function(ct, position)
23435 // Roo.log("Call onRender: " + this.xtype);
23437 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23439 this.el.dom.style.marginBottom = '0';
23441 var editorcore = this.editorcore;
23442 var editor= this.editor;
23445 var btn = function(id,cmd , toggle, handler, html){
23447 var event = toggle ? 'toggle' : 'click';
23452 xns: Roo.bootstrap,
23455 enableToggle:toggle !== false,
23457 pressed : toggle ? false : null,
23460 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23461 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23467 // var cb_box = function...
23472 xns: Roo.bootstrap,
23473 glyphicon : 'font',
23477 xns: Roo.bootstrap,
23481 Roo.each(this.formats, function(f) {
23482 style.menu.items.push({
23484 xns: Roo.bootstrap,
23485 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23490 editorcore.insertTag(this.tagname);
23497 children.push(style);
23499 btn('bold',false,true);
23500 btn('italic',false,true);
23501 btn('align-left', 'justifyleft',true);
23502 btn('align-center', 'justifycenter',true);
23503 btn('align-right' , 'justifyright',true);
23504 btn('link', false, false, function(btn) {
23505 //Roo.log("create link?");
23506 var url = prompt(this.createLinkText, this.defaultLinkValue);
23507 if(url && url != 'http:/'+'/'){
23508 this.editorcore.relayCmd('createlink', url);
23511 btn('list','insertunorderedlist',true);
23512 btn('pencil', false,true, function(btn){
23514 this.toggleSourceEdit(btn.pressed);
23517 if (this.editor.btns.length > 0) {
23518 for (var i = 0; i<this.editor.btns.length; i++) {
23519 children.push(this.editor.btns[i]);
23527 xns: Roo.bootstrap,
23532 xns: Roo.bootstrap,
23537 cog.menu.items.push({
23539 xns: Roo.bootstrap,
23540 html : Clean styles,
23545 editorcore.insertTag(this.tagname);
23554 this.xtype = 'NavSimplebar';
23556 for(var i=0;i< children.length;i++) {
23558 this.buttons.add(this.addxtypeChild(children[i]));
23562 editor.on('editorevent', this.updateToolbar, this);
23564 onBtnClick : function(id)
23566 this.editorcore.relayCmd(id);
23567 this.editorcore.focus();
23571 * Protected method that will not generally be called directly. It triggers
23572 * a toolbar update by reading the markup state of the current selection in the editor.
23574 updateToolbar: function(){
23576 if(!this.editorcore.activated){
23577 this.editor.onFirstFocus(); // is this neeed?
23581 var btns = this.buttons;
23582 var doc = this.editorcore.doc;
23583 btns.get('bold').setActive(doc.queryCommandState('bold'));
23584 btns.get('italic').setActive(doc.queryCommandState('italic'));
23585 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23587 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23588 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23589 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23591 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23592 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23595 var ans = this.editorcore.getAllAncestors();
23596 if (this.formatCombo) {
23599 var store = this.formatCombo.store;
23600 this.formatCombo.setValue("");
23601 for (var i =0; i < ans.length;i++) {
23602 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23604 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23612 // hides menus... - so this cant be on a menu...
23613 Roo.bootstrap.MenuMgr.hideAll();
23615 Roo.bootstrap.MenuMgr.hideAll();
23616 //this.editorsyncValue();
23618 onFirstFocus: function() {
23619 this.buttons.each(function(item){
23623 toggleSourceEdit : function(sourceEditMode){
23626 if(sourceEditMode){
23627 Roo.log("disabling buttons");
23628 this.buttons.each( function(item){
23629 if(item.cmd != 'pencil'){
23635 Roo.log("enabling buttons");
23636 if(this.editorcore.initialized){
23637 this.buttons.each( function(item){
23643 Roo.log("calling toggole on editor");
23644 // tell the editor that it's been pressed..
23645 this.editor.toggleSourceEdit(sourceEditMode);
23655 * @class Roo.bootstrap.Table.AbstractSelectionModel
23656 * @extends Roo.util.Observable
23657 * Abstract base class for grid SelectionModels. It provides the interface that should be
23658 * implemented by descendant classes. This class should not be directly instantiated.
23661 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23662 this.locked = false;
23663 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23667 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23668 /** @ignore Called by the grid automatically. Do not call directly. */
23669 init : function(grid){
23675 * Locks the selections.
23678 this.locked = true;
23682 * Unlocks the selections.
23684 unlock : function(){
23685 this.locked = false;
23689 * Returns true if the selections are locked.
23690 * @return {Boolean}
23692 isLocked : function(){
23693 return this.locked;
23697 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23698 * @class Roo.bootstrap.Table.RowSelectionModel
23699 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23700 * It supports multiple selections and keyboard selection/navigation.
23702 * @param {Object} config
23705 Roo.bootstrap.Table.RowSelectionModel = function(config){
23706 Roo.apply(this, config);
23707 this.selections = new Roo.util.MixedCollection(false, function(o){
23712 this.lastActive = false;
23716 * @event selectionchange
23717 * Fires when the selection changes
23718 * @param {SelectionModel} this
23720 "selectionchange" : true,
23722 * @event afterselectionchange
23723 * Fires after the selection changes (eg. by key press or clicking)
23724 * @param {SelectionModel} this
23726 "afterselectionchange" : true,
23728 * @event beforerowselect
23729 * Fires when a row is selected being selected, return false to cancel.
23730 * @param {SelectionModel} this
23731 * @param {Number} rowIndex The selected index
23732 * @param {Boolean} keepExisting False if other selections will be cleared
23734 "beforerowselect" : true,
23737 * Fires when a row is selected.
23738 * @param {SelectionModel} this
23739 * @param {Number} rowIndex The selected index
23740 * @param {Roo.data.Record} r The record
23742 "rowselect" : true,
23744 * @event rowdeselect
23745 * Fires when a row is deselected.
23746 * @param {SelectionModel} this
23747 * @param {Number} rowIndex The selected index
23749 "rowdeselect" : true
23751 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23752 this.locked = false;
23755 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23757 * @cfg {Boolean} singleSelect
23758 * True to allow selection of only one row at a time (defaults to false)
23760 singleSelect : false,
23763 initEvents : function()
23766 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23767 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23768 //}else{ // allow click to work like normal
23769 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23771 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23772 this.grid.on("rowclick", this.handleMouseDown, this);
23774 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23775 "up" : function(e){
23777 this.selectPrevious(e.shiftKey);
23778 }else if(this.last !== false && this.lastActive !== false){
23779 var last = this.last;
23780 this.selectRange(this.last, this.lastActive-1);
23781 this.grid.getView().focusRow(this.lastActive);
23782 if(last !== false){
23786 this.selectFirstRow();
23788 this.fireEvent("afterselectionchange", this);
23790 "down" : function(e){
23792 this.selectNext(e.shiftKey);
23793 }else if(this.last !== false && this.lastActive !== false){
23794 var last = this.last;
23795 this.selectRange(this.last, this.lastActive+1);
23796 this.grid.getView().focusRow(this.lastActive);
23797 if(last !== false){
23801 this.selectFirstRow();
23803 this.fireEvent("afterselectionchange", this);
23807 this.grid.store.on('load', function(){
23808 this.selections.clear();
23811 var view = this.grid.view;
23812 view.on("refresh", this.onRefresh, this);
23813 view.on("rowupdated", this.onRowUpdated, this);
23814 view.on("rowremoved", this.onRemove, this);
23819 onRefresh : function()
23821 var ds = this.grid.store, i, v = this.grid.view;
23822 var s = this.selections;
23823 s.each(function(r){
23824 if((i = ds.indexOfId(r.id)) != -1){
23833 onRemove : function(v, index, r){
23834 this.selections.remove(r);
23838 onRowUpdated : function(v, index, r){
23839 if(this.isSelected(r)){
23840 v.onRowSelect(index);
23846 * @param {Array} records The records to select
23847 * @param {Boolean} keepExisting (optional) True to keep existing selections
23849 selectRecords : function(records, keepExisting)
23852 this.clearSelections();
23854 var ds = this.grid.store;
23855 for(var i = 0, len = records.length; i < len; i++){
23856 this.selectRow(ds.indexOf(records[i]), true);
23861 * Gets the number of selected rows.
23864 getCount : function(){
23865 return this.selections.length;
23869 * Selects the first row in the grid.
23871 selectFirstRow : function(){
23876 * Select the last row.
23877 * @param {Boolean} keepExisting (optional) True to keep existing selections
23879 selectLastRow : function(keepExisting){
23880 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23881 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23885 * Selects the row immediately following the last selected row.
23886 * @param {Boolean} keepExisting (optional) True to keep existing selections
23888 selectNext : function(keepExisting)
23890 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23891 this.selectRow(this.last+1, keepExisting);
23892 this.grid.getView().focusRow(this.last);
23897 * Selects the row that precedes the last selected row.
23898 * @param {Boolean} keepExisting (optional) True to keep existing selections
23900 selectPrevious : function(keepExisting){
23902 this.selectRow(this.last-1, keepExisting);
23903 this.grid.getView().focusRow(this.last);
23908 * Returns the selected records
23909 * @return {Array} Array of selected records
23911 getSelections : function(){
23912 return [].concat(this.selections.items);
23916 * Returns the first selected record.
23919 getSelected : function(){
23920 return this.selections.itemAt(0);
23925 * Clears all selections.
23927 clearSelections : function(fast)
23933 var ds = this.grid.store;
23934 var s = this.selections;
23935 s.each(function(r){
23936 this.deselectRow(ds.indexOfId(r.id));
23940 this.selections.clear();
23947 * Selects all rows.
23949 selectAll : function(){
23953 this.selections.clear();
23954 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23955 this.selectRow(i, true);
23960 * Returns True if there is a selection.
23961 * @return {Boolean}
23963 hasSelection : function(){
23964 return this.selections.length > 0;
23968 * Returns True if the specified row is selected.
23969 * @param {Number/Record} record The record or index of the record to check
23970 * @return {Boolean}
23972 isSelected : function(index){
23973 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23974 return (r && this.selections.key(r.id) ? true : false);
23978 * Returns True if the specified record id is selected.
23979 * @param {String} id The id of record to check
23980 * @return {Boolean}
23982 isIdSelected : function(id){
23983 return (this.selections.key(id) ? true : false);
23988 handleMouseDBClick : function(e, t){
23992 handleMouseDown : function(e, t)
23994 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23995 if(this.isLocked() || rowIndex < 0 ){
23998 if(e.shiftKey && this.last !== false){
23999 var last = this.last;
24000 this.selectRange(last, rowIndex, e.ctrlKey);
24001 this.last = last; // reset the last
24005 var isSelected = this.isSelected(rowIndex);
24006 //Roo.log("select row:" + rowIndex);
24008 this.deselectRow(rowIndex);
24010 this.selectRow(rowIndex, true);
24014 if(e.button !== 0 && isSelected){
24015 alert('rowIndex 2: ' + rowIndex);
24016 view.focusRow(rowIndex);
24017 }else if(e.ctrlKey && isSelected){
24018 this.deselectRow(rowIndex);
24019 }else if(!isSelected){
24020 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24021 view.focusRow(rowIndex);
24025 this.fireEvent("afterselectionchange", this);
24028 handleDragableRowClick : function(grid, rowIndex, e)
24030 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24031 this.selectRow(rowIndex, false);
24032 grid.view.focusRow(rowIndex);
24033 this.fireEvent("afterselectionchange", this);
24038 * Selects multiple rows.
24039 * @param {Array} rows Array of the indexes of the row to select
24040 * @param {Boolean} keepExisting (optional) True to keep existing selections
24042 selectRows : function(rows, keepExisting){
24044 this.clearSelections();
24046 for(var i = 0, len = rows.length; i < len; i++){
24047 this.selectRow(rows[i], true);
24052 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24053 * @param {Number} startRow The index of the first row in the range
24054 * @param {Number} endRow The index of the last row in the range
24055 * @param {Boolean} keepExisting (optional) True to retain existing selections
24057 selectRange : function(startRow, endRow, keepExisting){
24062 this.clearSelections();
24064 if(startRow <= endRow){
24065 for(var i = startRow; i <= endRow; i++){
24066 this.selectRow(i, true);
24069 for(var i = startRow; i >= endRow; i--){
24070 this.selectRow(i, true);
24076 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24077 * @param {Number} startRow The index of the first row in the range
24078 * @param {Number} endRow The index of the last row in the range
24080 deselectRange : function(startRow, endRow, preventViewNotify){
24084 for(var i = startRow; i <= endRow; i++){
24085 this.deselectRow(i, preventViewNotify);
24091 * @param {Number} row The index of the row to select
24092 * @param {Boolean} keepExisting (optional) True to keep existing selections
24094 selectRow : function(index, keepExisting, preventViewNotify)
24096 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24099 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24100 if(!keepExisting || this.singleSelect){
24101 this.clearSelections();
24104 var r = this.grid.store.getAt(index);
24105 //console.log('selectRow - record id :' + r.id);
24107 this.selections.add(r);
24108 this.last = this.lastActive = index;
24109 if(!preventViewNotify){
24110 var proxy = new Roo.Element(
24111 this.grid.getRowDom(index)
24113 proxy.addClass('bg-info info');
24115 this.fireEvent("rowselect", this, index, r);
24116 this.fireEvent("selectionchange", this);
24122 * @param {Number} row The index of the row to deselect
24124 deselectRow : function(index, preventViewNotify)
24129 if(this.last == index){
24132 if(this.lastActive == index){
24133 this.lastActive = false;
24136 var r = this.grid.store.getAt(index);
24141 this.selections.remove(r);
24142 //.console.log('deselectRow - record id :' + r.id);
24143 if(!preventViewNotify){
24145 var proxy = new Roo.Element(
24146 this.grid.getRowDom(index)
24148 proxy.removeClass('bg-info info');
24150 this.fireEvent("rowdeselect", this, index);
24151 this.fireEvent("selectionchange", this);
24155 restoreLast : function(){
24157 this.last = this._last;
24162 acceptsNav : function(row, col, cm){
24163 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24167 onEditorKey : function(field, e){
24168 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24173 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24175 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24177 }else if(k == e.ENTER && !e.ctrlKey){
24181 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24183 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24185 }else if(k == e.ESC){
24189 g.startEditing(newCell[0], newCell[1]);
24195 * Ext JS Library 1.1.1
24196 * Copyright(c) 2006-2007, Ext JS, LLC.
24198 * Originally Released Under LGPL - original licence link has changed is not relivant.
24201 * <script type="text/javascript">
24205 * @class Roo.bootstrap.PagingToolbar
24206 * @extends Roo.bootstrap.NavSimplebar
24207 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24209 * Create a new PagingToolbar
24210 * @param {Object} config The config object
24211 * @param {Roo.data.Store} store
24213 Roo.bootstrap.PagingToolbar = function(config)
24215 // old args format still supported... - xtype is prefered..
24216 // created from xtype...
24218 this.ds = config.dataSource;
24220 if (config.store && !this.ds) {
24221 this.store= Roo.factory(config.store, Roo.data);
24222 this.ds = this.store;
24223 this.ds.xmodule = this.xmodule || false;
24226 this.toolbarItems = [];
24227 if (config.items) {
24228 this.toolbarItems = config.items;
24231 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24236 this.bind(this.ds);
24239 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24243 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24245 * @cfg {Roo.data.Store} dataSource
24246 * The underlying data store providing the paged data
24249 * @cfg {String/HTMLElement/Element} container
24250 * container The id or element that will contain the toolbar
24253 * @cfg {Boolean} displayInfo
24254 * True to display the displayMsg (defaults to false)
24257 * @cfg {Number} pageSize
24258 * The number of records to display per page (defaults to 20)
24262 * @cfg {String} displayMsg
24263 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24265 displayMsg : 'Displaying {0} - {1} of {2}',
24267 * @cfg {String} emptyMsg
24268 * The message to display when no records are found (defaults to "No data to display")
24270 emptyMsg : 'No data to display',
24272 * Customizable piece of the default paging text (defaults to "Page")
24275 beforePageText : "Page",
24277 * Customizable piece of the default paging text (defaults to "of %0")
24280 afterPageText : "of {0}",
24282 * Customizable piece of the default paging text (defaults to "First Page")
24285 firstText : "First Page",
24287 * Customizable piece of the default paging text (defaults to "Previous Page")
24290 prevText : "Previous Page",
24292 * Customizable piece of the default paging text (defaults to "Next Page")
24295 nextText : "Next Page",
24297 * Customizable piece of the default paging text (defaults to "Last Page")
24300 lastText : "Last Page",
24302 * Customizable piece of the default paging text (defaults to "Refresh")
24305 refreshText : "Refresh",
24309 onRender : function(ct, position)
24311 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24312 this.navgroup.parentId = this.id;
24313 this.navgroup.onRender(this.el, null);
24314 // add the buttons to the navgroup
24316 if(this.displayInfo){
24317 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24318 this.displayEl = this.el.select('.x-paging-info', true).first();
24319 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24320 // this.displayEl = navel.el.select('span',true).first();
24326 Roo.each(_this.buttons, function(e){ // this might need to use render????
24327 Roo.factory(e).onRender(_this.el, null);
24331 Roo.each(_this.toolbarItems, function(e) {
24332 _this.navgroup.addItem(e);
24336 this.first = this.navgroup.addItem({
24337 tooltip: this.firstText,
24339 icon : 'fa fa-backward',
24341 preventDefault: true,
24342 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24345 this.prev = this.navgroup.addItem({
24346 tooltip: this.prevText,
24348 icon : 'fa fa-step-backward',
24350 preventDefault: true,
24351 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24353 //this.addSeparator();
24356 var field = this.navgroup.addItem( {
24358 cls : 'x-paging-position',
24360 html : this.beforePageText +
24361 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24362 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24365 this.field = field.el.select('input', true).first();
24366 this.field.on("keydown", this.onPagingKeydown, this);
24367 this.field.on("focus", function(){this.dom.select();});
24370 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24371 //this.field.setHeight(18);
24372 //this.addSeparator();
24373 this.next = this.navgroup.addItem({
24374 tooltip: this.nextText,
24376 html : ' <i class="fa fa-step-forward">',
24378 preventDefault: true,
24379 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24381 this.last = this.navgroup.addItem({
24382 tooltip: this.lastText,
24383 icon : 'fa fa-forward',
24386 preventDefault: true,
24387 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24389 //this.addSeparator();
24390 this.loading = this.navgroup.addItem({
24391 tooltip: this.refreshText,
24392 icon: 'fa fa-refresh',
24393 preventDefault: true,
24394 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24400 updateInfo : function(){
24401 if(this.displayEl){
24402 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24403 var msg = count == 0 ?
24407 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24409 this.displayEl.update(msg);
24414 onLoad : function(ds, r, o)
24416 this.cursor = o.params ? o.params.start : 0;
24417 var d = this.getPageData(),
24422 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24423 this.field.dom.value = ap;
24424 this.first.setDisabled(ap == 1);
24425 this.prev.setDisabled(ap == 1);
24426 this.next.setDisabled(ap == ps);
24427 this.last.setDisabled(ap == ps);
24428 this.loading.enable();
24433 getPageData : function(){
24434 var total = this.ds.getTotalCount();
24437 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24438 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24443 onLoadError : function(){
24444 this.loading.enable();
24448 onPagingKeydown : function(e){
24449 var k = e.getKey();
24450 var d = this.getPageData();
24452 var v = this.field.dom.value, pageNum;
24453 if(!v || isNaN(pageNum = parseInt(v, 10))){
24454 this.field.dom.value = d.activePage;
24457 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24458 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24461 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))
24463 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24464 this.field.dom.value = pageNum;
24465 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24468 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24470 var v = this.field.dom.value, pageNum;
24471 var increment = (e.shiftKey) ? 10 : 1;
24472 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24475 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24476 this.field.dom.value = d.activePage;
24479 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24481 this.field.dom.value = parseInt(v, 10) + increment;
24482 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24483 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24490 beforeLoad : function(){
24492 this.loading.disable();
24497 onClick : function(which){
24506 ds.load({params:{start: 0, limit: this.pageSize}});
24509 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24512 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24515 var total = ds.getTotalCount();
24516 var extra = total % this.pageSize;
24517 var lastStart = extra ? (total - extra) : total-this.pageSize;
24518 ds.load({params:{start: lastStart, limit: this.pageSize}});
24521 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24527 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24528 * @param {Roo.data.Store} store The data store to unbind
24530 unbind : function(ds){
24531 ds.un("beforeload", this.beforeLoad, this);
24532 ds.un("load", this.onLoad, this);
24533 ds.un("loadexception", this.onLoadError, this);
24534 ds.un("remove", this.updateInfo, this);
24535 ds.un("add", this.updateInfo, this);
24536 this.ds = undefined;
24540 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24541 * @param {Roo.data.Store} store The data store to bind
24543 bind : function(ds){
24544 ds.on("beforeload", this.beforeLoad, this);
24545 ds.on("load", this.onLoad, this);
24546 ds.on("loadexception", this.onLoadError, this);
24547 ds.on("remove", this.updateInfo, this);
24548 ds.on("add", this.updateInfo, this);
24559 * @class Roo.bootstrap.MessageBar
24560 * @extends Roo.bootstrap.Component
24561 * Bootstrap MessageBar class
24562 * @cfg {String} html contents of the MessageBar
24563 * @cfg {String} weight (info | success | warning | danger) default info
24564 * @cfg {String} beforeClass insert the bar before the given class
24565 * @cfg {Boolean} closable (true | false) default false
24566 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24569 * Create a new Element
24570 * @param {Object} config The config object
24573 Roo.bootstrap.MessageBar = function(config){
24574 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24577 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24583 beforeClass: 'bootstrap-sticky-wrap',
24585 getAutoCreate : function(){
24589 cls: 'alert alert-dismissable alert-' + this.weight,
24594 html: this.html || ''
24600 cfg.cls += ' alert-messages-fixed';
24614 onRender : function(ct, position)
24616 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24619 var cfg = Roo.apply({}, this.getAutoCreate());
24623 cfg.cls += ' ' + this.cls;
24626 cfg.style = this.style;
24628 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24630 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24633 this.el.select('>button.close').on('click', this.hide, this);
24639 if (!this.rendered) {
24645 this.fireEvent('show', this);
24651 if (!this.rendered) {
24657 this.fireEvent('hide', this);
24660 update : function()
24662 // var e = this.el.dom.firstChild;
24664 // if(this.closable){
24665 // e = e.nextSibling;
24668 // e.data = this.html || '';
24670 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24686 * @class Roo.bootstrap.Graph
24687 * @extends Roo.bootstrap.Component
24688 * Bootstrap Graph class
24692 @cfg {String} graphtype bar | vbar | pie
24693 @cfg {number} g_x coodinator | centre x (pie)
24694 @cfg {number} g_y coodinator | centre y (pie)
24695 @cfg {number} g_r radius (pie)
24696 @cfg {number} g_height height of the chart (respected by all elements in the set)
24697 @cfg {number} g_width width of the chart (respected by all elements in the set)
24698 @cfg {Object} title The title of the chart
24701 -opts (object) options for the chart
24703 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24704 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24706 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.
24707 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24709 o stretch (boolean)
24711 -opts (object) options for the pie
24714 o startAngle (number)
24715 o endAngle (number)
24719 * Create a new Input
24720 * @param {Object} config The config object
24723 Roo.bootstrap.Graph = function(config){
24724 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24730 * The img click event for the img.
24731 * @param {Roo.EventObject} e
24737 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24748 //g_colors: this.colors,
24755 getAutoCreate : function(){
24766 onRender : function(ct,position){
24769 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24771 if (typeof(Raphael) == 'undefined') {
24772 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24776 this.raphael = Raphael(this.el.dom);
24778 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24779 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24780 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24781 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24783 r.text(160, 10, "Single Series Chart").attr(txtattr);
24784 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24785 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24786 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24788 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24789 r.barchart(330, 10, 300, 220, data1);
24790 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24791 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24794 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24795 // r.barchart(30, 30, 560, 250, xdata, {
24796 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24797 // axis : "0 0 1 1",
24798 // axisxlabels : xdata
24799 // //yvalues : cols,
24802 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24804 // this.load(null,xdata,{
24805 // axis : "0 0 1 1",
24806 // axisxlabels : xdata
24811 load : function(graphtype,xdata,opts)
24813 this.raphael.clear();
24815 graphtype = this.graphtype;
24820 var r = this.raphael,
24821 fin = function () {
24822 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24824 fout = function () {
24825 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24827 pfin = function() {
24828 this.sector.stop();
24829 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24832 this.label[0].stop();
24833 this.label[0].attr({ r: 7.5 });
24834 this.label[1].attr({ "font-weight": 800 });
24837 pfout = function() {
24838 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24841 this.label[0].animate({ r: 5 }, 500, "bounce");
24842 this.label[1].attr({ "font-weight": 400 });
24848 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24851 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24854 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24855 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24857 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24864 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24869 setTitle: function(o)
24874 initEvents: function() {
24877 this.el.on('click', this.onClick, this);
24881 onClick : function(e)
24883 Roo.log('img onclick');
24884 this.fireEvent('click', this, e);
24896 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24899 * @class Roo.bootstrap.dash.NumberBox
24900 * @extends Roo.bootstrap.Component
24901 * Bootstrap NumberBox class
24902 * @cfg {String} headline Box headline
24903 * @cfg {String} content Box content
24904 * @cfg {String} icon Box icon
24905 * @cfg {String} footer Footer text
24906 * @cfg {String} fhref Footer href
24909 * Create a new NumberBox
24910 * @param {Object} config The config object
24914 Roo.bootstrap.dash.NumberBox = function(config){
24915 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24919 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24928 getAutoCreate : function(){
24932 cls : 'small-box ',
24940 cls : 'roo-headline',
24941 html : this.headline
24945 cls : 'roo-content',
24946 html : this.content
24960 cls : 'ion ' + this.icon
24969 cls : 'small-box-footer',
24970 href : this.fhref || '#',
24974 cfg.cn.push(footer);
24981 onRender : function(ct,position){
24982 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24989 setHeadline: function (value)
24991 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24994 setFooter: function (value, href)
24996 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24999 this.el.select('a.small-box-footer',true).first().attr('href', href);
25004 setContent: function (value)
25006 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25009 initEvents: function()
25023 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25026 * @class Roo.bootstrap.dash.TabBox
25027 * @extends Roo.bootstrap.Component
25028 * Bootstrap TabBox class
25029 * @cfg {String} title Title of the TabBox
25030 * @cfg {String} icon Icon of the TabBox
25031 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25032 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25035 * Create a new TabBox
25036 * @param {Object} config The config object
25040 Roo.bootstrap.dash.TabBox = function(config){
25041 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25046 * When a pane is added
25047 * @param {Roo.bootstrap.dash.TabPane} pane
25051 * @event activatepane
25052 * When a pane is activated
25053 * @param {Roo.bootstrap.dash.TabPane} pane
25055 "activatepane" : true
25063 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25068 tabScrollable : false,
25070 getChildContainer : function()
25072 return this.el.select('.tab-content', true).first();
25075 getAutoCreate : function(){
25079 cls: 'pull-left header',
25087 cls: 'fa ' + this.icon
25093 cls: 'nav nav-tabs pull-right',
25099 if(this.tabScrollable){
25106 cls: 'nav nav-tabs pull-right',
25117 cls: 'nav-tabs-custom',
25122 cls: 'tab-content no-padding',
25130 initEvents : function()
25132 //Roo.log('add add pane handler');
25133 this.on('addpane', this.onAddPane, this);
25136 * Updates the box title
25137 * @param {String} html to set the title to.
25139 setTitle : function(value)
25141 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25143 onAddPane : function(pane)
25145 this.panes.push(pane);
25146 //Roo.log('addpane');
25148 // tabs are rendere left to right..
25149 if(!this.showtabs){
25153 var ctr = this.el.select('.nav-tabs', true).first();
25156 var existing = ctr.select('.nav-tab',true);
25157 var qty = existing.getCount();;
25160 var tab = ctr.createChild({
25162 cls : 'nav-tab' + (qty ? '' : ' active'),
25170 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25173 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25175 pane.el.addClass('active');
25180 onTabClick : function(ev,un,ob,pane)
25182 //Roo.log('tab - prev default');
25183 ev.preventDefault();
25186 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25187 pane.tab.addClass('active');
25188 //Roo.log(pane.title);
25189 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25190 // technically we should have a deactivate event.. but maybe add later.
25191 // and it should not de-activate the selected tab...
25192 this.fireEvent('activatepane', pane);
25193 pane.el.addClass('active');
25194 pane.fireEvent('activate');
25199 getActivePane : function()
25202 Roo.each(this.panes, function(p) {
25203 if(p.el.hasClass('active')){
25224 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25226 * @class Roo.bootstrap.TabPane
25227 * @extends Roo.bootstrap.Component
25228 * Bootstrap TabPane class
25229 * @cfg {Boolean} active (false | true) Default false
25230 * @cfg {String} title title of panel
25234 * Create a new TabPane
25235 * @param {Object} config The config object
25238 Roo.bootstrap.dash.TabPane = function(config){
25239 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25245 * When a pane is activated
25246 * @param {Roo.bootstrap.dash.TabPane} pane
25253 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25258 // the tabBox that this is attached to.
25261 getAutoCreate : function()
25269 cfg.cls += ' active';
25274 initEvents : function()
25276 //Roo.log('trigger add pane handler');
25277 this.parent().fireEvent('addpane', this)
25281 * Updates the tab title
25282 * @param {String} html to set the title to.
25284 setTitle: function(str)
25290 this.tab.select('a', true).first().dom.innerHTML = str;
25307 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25310 * @class Roo.bootstrap.menu.Menu
25311 * @extends Roo.bootstrap.Component
25312 * Bootstrap Menu class - container for Menu
25313 * @cfg {String} html Text of the menu
25314 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25315 * @cfg {String} icon Font awesome icon
25316 * @cfg {String} pos Menu align to (top | bottom) default bottom
25320 * Create a new Menu
25321 * @param {Object} config The config object
25325 Roo.bootstrap.menu.Menu = function(config){
25326 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25330 * @event beforeshow
25331 * Fires before this menu is displayed
25332 * @param {Roo.bootstrap.menu.Menu} this
25336 * @event beforehide
25337 * Fires before this menu is hidden
25338 * @param {Roo.bootstrap.menu.Menu} this
25343 * Fires after this menu is displayed
25344 * @param {Roo.bootstrap.menu.Menu} this
25349 * Fires after this menu is hidden
25350 * @param {Roo.bootstrap.menu.Menu} this
25355 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25356 * @param {Roo.bootstrap.menu.Menu} this
25357 * @param {Roo.EventObject} e
25364 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25368 weight : 'default',
25373 getChildContainer : function() {
25374 if(this.isSubMenu){
25378 return this.el.select('ul.dropdown-menu', true).first();
25381 getAutoCreate : function()
25386 cls : 'roo-menu-text',
25394 cls : 'fa ' + this.icon
25405 cls : 'dropdown-button btn btn-' + this.weight,
25410 cls : 'dropdown-toggle btn btn-' + this.weight,
25420 cls : 'dropdown-menu'
25426 if(this.pos == 'top'){
25427 cfg.cls += ' dropup';
25430 if(this.isSubMenu){
25433 cls : 'dropdown-menu'
25440 onRender : function(ct, position)
25442 this.isSubMenu = ct.hasClass('dropdown-submenu');
25444 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25447 initEvents : function()
25449 if(this.isSubMenu){
25453 this.hidden = true;
25455 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25456 this.triggerEl.on('click', this.onTriggerPress, this);
25458 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25459 this.buttonEl.on('click', this.onClick, this);
25465 if(this.isSubMenu){
25469 return this.el.select('ul.dropdown-menu', true).first();
25472 onClick : function(e)
25474 this.fireEvent("click", this, e);
25477 onTriggerPress : function(e)
25479 if (this.isVisible()) {
25486 isVisible : function(){
25487 return !this.hidden;
25492 this.fireEvent("beforeshow", this);
25494 this.hidden = false;
25495 this.el.addClass('open');
25497 Roo.get(document).on("mouseup", this.onMouseUp, this);
25499 this.fireEvent("show", this);
25506 this.fireEvent("beforehide", this);
25508 this.hidden = true;
25509 this.el.removeClass('open');
25511 Roo.get(document).un("mouseup", this.onMouseUp);
25513 this.fireEvent("hide", this);
25516 onMouseUp : function()
25530 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25533 * @class Roo.bootstrap.menu.Item
25534 * @extends Roo.bootstrap.Component
25535 * Bootstrap MenuItem class
25536 * @cfg {Boolean} submenu (true | false) default false
25537 * @cfg {String} html text of the item
25538 * @cfg {String} href the link
25539 * @cfg {Boolean} disable (true | false) default false
25540 * @cfg {Boolean} preventDefault (true | false) default true
25541 * @cfg {String} icon Font awesome icon
25542 * @cfg {String} pos Submenu align to (left | right) default right
25546 * Create a new Item
25547 * @param {Object} config The config object
25551 Roo.bootstrap.menu.Item = function(config){
25552 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25556 * Fires when the mouse is hovering over this menu
25557 * @param {Roo.bootstrap.menu.Item} this
25558 * @param {Roo.EventObject} e
25563 * Fires when the mouse exits this menu
25564 * @param {Roo.bootstrap.menu.Item} this
25565 * @param {Roo.EventObject} e
25571 * The raw click event for the entire grid.
25572 * @param {Roo.EventObject} e
25578 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25583 preventDefault: true,
25588 getAutoCreate : function()
25593 cls : 'roo-menu-item-text',
25601 cls : 'fa ' + this.icon
25610 href : this.href || '#',
25617 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25621 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25623 if(this.pos == 'left'){
25624 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25631 initEvents : function()
25633 this.el.on('mouseover', this.onMouseOver, this);
25634 this.el.on('mouseout', this.onMouseOut, this);
25636 this.el.select('a', true).first().on('click', this.onClick, this);
25640 onClick : function(e)
25642 if(this.preventDefault){
25643 e.preventDefault();
25646 this.fireEvent("click", this, e);
25649 onMouseOver : function(e)
25651 if(this.submenu && this.pos == 'left'){
25652 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25655 this.fireEvent("mouseover", this, e);
25658 onMouseOut : function(e)
25660 this.fireEvent("mouseout", this, e);
25672 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25675 * @class Roo.bootstrap.menu.Separator
25676 * @extends Roo.bootstrap.Component
25677 * Bootstrap Separator class
25680 * Create a new Separator
25681 * @param {Object} config The config object
25685 Roo.bootstrap.menu.Separator = function(config){
25686 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25689 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25691 getAutoCreate : function(){
25712 * @class Roo.bootstrap.Tooltip
25713 * Bootstrap Tooltip class
25714 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25715 * to determine which dom element triggers the tooltip.
25717 * It needs to add support for additional attributes like tooltip-position
25720 * Create a new Toolti
25721 * @param {Object} config The config object
25724 Roo.bootstrap.Tooltip = function(config){
25725 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25727 this.alignment = Roo.bootstrap.Tooltip.alignment;
25729 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25730 this.alignment = config.alignment;
25735 Roo.apply(Roo.bootstrap.Tooltip, {
25737 * @function init initialize tooltip monitoring.
25741 currentTip : false,
25742 currentRegion : false,
25748 Roo.get(document).on('mouseover', this.enter ,this);
25749 Roo.get(document).on('mouseout', this.leave, this);
25752 this.currentTip = new Roo.bootstrap.Tooltip();
25755 enter : function(ev)
25757 var dom = ev.getTarget();
25759 //Roo.log(['enter',dom]);
25760 var el = Roo.fly(dom);
25761 if (this.currentEl) {
25763 //Roo.log(this.currentEl);
25764 //Roo.log(this.currentEl.contains(dom));
25765 if (this.currentEl == el) {
25768 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25774 if (this.currentTip.el) {
25775 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25779 if(!el || el.dom == document){
25785 // you can not look for children, as if el is the body.. then everythign is the child..
25786 if (!el.attr('tooltip')) { //
25787 if (!el.select("[tooltip]").elements.length) {
25790 // is the mouse over this child...?
25791 bindEl = el.select("[tooltip]").first();
25792 var xy = ev.getXY();
25793 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25794 //Roo.log("not in region.");
25797 //Roo.log("child element over..");
25800 this.currentEl = bindEl;
25801 this.currentTip.bind(bindEl);
25802 this.currentRegion = Roo.lib.Region.getRegion(dom);
25803 this.currentTip.enter();
25806 leave : function(ev)
25808 var dom = ev.getTarget();
25809 //Roo.log(['leave',dom]);
25810 if (!this.currentEl) {
25815 if (dom != this.currentEl.dom) {
25818 var xy = ev.getXY();
25819 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25822 // only activate leave if mouse cursor is outside... bounding box..
25827 if (this.currentTip) {
25828 this.currentTip.leave();
25830 //Roo.log('clear currentEl');
25831 this.currentEl = false;
25836 'left' : ['r-l', [-2,0], 'right'],
25837 'right' : ['l-r', [2,0], 'left'],
25838 'bottom' : ['t-b', [0,2], 'top'],
25839 'top' : [ 'b-t', [0,-2], 'bottom']
25845 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25850 delay : null, // can be { show : 300 , hide: 500}
25854 hoverState : null, //???
25856 placement : 'bottom',
25860 getAutoCreate : function(){
25867 cls : 'tooltip-arrow'
25870 cls : 'tooltip-inner'
25877 bind : function(el)
25883 enter : function () {
25885 if (this.timeout != null) {
25886 clearTimeout(this.timeout);
25889 this.hoverState = 'in';
25890 //Roo.log("enter - show");
25891 if (!this.delay || !this.delay.show) {
25896 this.timeout = setTimeout(function () {
25897 if (_t.hoverState == 'in') {
25900 }, this.delay.show);
25904 clearTimeout(this.timeout);
25906 this.hoverState = 'out';
25907 if (!this.delay || !this.delay.hide) {
25913 this.timeout = setTimeout(function () {
25914 //Roo.log("leave - timeout");
25916 if (_t.hoverState == 'out') {
25918 Roo.bootstrap.Tooltip.currentEl = false;
25923 show : function (msg)
25926 this.render(document.body);
25929 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25931 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25933 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25935 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25937 var placement = typeof this.placement == 'function' ?
25938 this.placement.call(this, this.el, on_el) :
25941 var autoToken = /\s?auto?\s?/i;
25942 var autoPlace = autoToken.test(placement);
25944 placement = placement.replace(autoToken, '') || 'top';
25948 //this.el.setXY([0,0]);
25950 //this.el.dom.style.display='block';
25952 //this.el.appendTo(on_el);
25954 var p = this.getPosition();
25955 var box = this.el.getBox();
25961 var align = this.alignment[placement];
25963 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25965 if(placement == 'top' || placement == 'bottom'){
25967 placement = 'right';
25970 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25971 placement = 'left';
25974 var scroll = Roo.select('body', true).first().getScroll();
25976 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25982 this.el.alignTo(this.bindEl, align[0],align[1]);
25983 //var arrow = this.el.select('.arrow',true).first();
25984 //arrow.set(align[2],
25986 this.el.addClass(placement);
25988 this.el.addClass('in fade');
25990 this.hoverState = null;
25992 if (this.el.hasClass('fade')) {
26003 //this.el.setXY([0,0]);
26004 this.el.removeClass('in');
26020 * @class Roo.bootstrap.LocationPicker
26021 * @extends Roo.bootstrap.Component
26022 * Bootstrap LocationPicker class
26023 * @cfg {Number} latitude Position when init default 0
26024 * @cfg {Number} longitude Position when init default 0
26025 * @cfg {Number} zoom default 15
26026 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26027 * @cfg {Boolean} mapTypeControl default false
26028 * @cfg {Boolean} disableDoubleClickZoom default false
26029 * @cfg {Boolean} scrollwheel default true
26030 * @cfg {Boolean} streetViewControl default false
26031 * @cfg {Number} radius default 0
26032 * @cfg {String} locationName
26033 * @cfg {Boolean} draggable default true
26034 * @cfg {Boolean} enableAutocomplete default false
26035 * @cfg {Boolean} enableReverseGeocode default true
26036 * @cfg {String} markerTitle
26039 * Create a new LocationPicker
26040 * @param {Object} config The config object
26044 Roo.bootstrap.LocationPicker = function(config){
26046 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26051 * Fires when the picker initialized.
26052 * @param {Roo.bootstrap.LocationPicker} this
26053 * @param {Google Location} location
26057 * @event positionchanged
26058 * Fires when the picker position changed.
26059 * @param {Roo.bootstrap.LocationPicker} this
26060 * @param {Google Location} location
26062 positionchanged : true,
26065 * Fires when the map resize.
26066 * @param {Roo.bootstrap.LocationPicker} this
26071 * Fires when the map show.
26072 * @param {Roo.bootstrap.LocationPicker} this
26077 * Fires when the map hide.
26078 * @param {Roo.bootstrap.LocationPicker} this
26083 * Fires when click the map.
26084 * @param {Roo.bootstrap.LocationPicker} this
26085 * @param {Map event} e
26089 * @event mapRightClick
26090 * Fires when right click the map.
26091 * @param {Roo.bootstrap.LocationPicker} this
26092 * @param {Map event} e
26094 mapRightClick : true,
26096 * @event markerClick
26097 * Fires when click the marker.
26098 * @param {Roo.bootstrap.LocationPicker} this
26099 * @param {Map event} e
26101 markerClick : true,
26103 * @event markerRightClick
26104 * Fires when right click the marker.
26105 * @param {Roo.bootstrap.LocationPicker} this
26106 * @param {Map event} e
26108 markerRightClick : true,
26110 * @event OverlayViewDraw
26111 * Fires when OverlayView Draw
26112 * @param {Roo.bootstrap.LocationPicker} this
26114 OverlayViewDraw : true,
26116 * @event OverlayViewOnAdd
26117 * Fires when OverlayView Draw
26118 * @param {Roo.bootstrap.LocationPicker} this
26120 OverlayViewOnAdd : true,
26122 * @event OverlayViewOnRemove
26123 * Fires when OverlayView Draw
26124 * @param {Roo.bootstrap.LocationPicker} this
26126 OverlayViewOnRemove : true,
26128 * @event OverlayViewShow
26129 * Fires when OverlayView Draw
26130 * @param {Roo.bootstrap.LocationPicker} this
26131 * @param {Pixel} cpx
26133 OverlayViewShow : true,
26135 * @event OverlayViewHide
26136 * Fires when OverlayView Draw
26137 * @param {Roo.bootstrap.LocationPicker} this
26139 OverlayViewHide : true,
26141 * @event loadexception
26142 * Fires when load google lib failed.
26143 * @param {Roo.bootstrap.LocationPicker} this
26145 loadexception : true
26150 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26152 gMapContext: false,
26158 mapTypeControl: false,
26159 disableDoubleClickZoom: false,
26161 streetViewControl: false,
26165 enableAutocomplete: false,
26166 enableReverseGeocode: true,
26169 getAutoCreate: function()
26174 cls: 'roo-location-picker'
26180 initEvents: function(ct, position)
26182 if(!this.el.getWidth() || this.isApplied()){
26186 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26191 initial: function()
26193 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26194 this.fireEvent('loadexception', this);
26198 if(!this.mapTypeId){
26199 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26202 this.gMapContext = this.GMapContext();
26204 this.initOverlayView();
26206 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26210 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26211 _this.setPosition(_this.gMapContext.marker.position);
26214 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26215 _this.fireEvent('mapClick', this, event);
26219 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26220 _this.fireEvent('mapRightClick', this, event);
26224 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26225 _this.fireEvent('markerClick', this, event);
26229 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26230 _this.fireEvent('markerRightClick', this, event);
26234 this.setPosition(this.gMapContext.location);
26236 this.fireEvent('initial', this, this.gMapContext.location);
26239 initOverlayView: function()
26243 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26247 _this.fireEvent('OverlayViewDraw', _this);
26252 _this.fireEvent('OverlayViewOnAdd', _this);
26255 onRemove: function()
26257 _this.fireEvent('OverlayViewOnRemove', _this);
26260 show: function(cpx)
26262 _this.fireEvent('OverlayViewShow', _this, cpx);
26267 _this.fireEvent('OverlayViewHide', _this);
26273 fromLatLngToContainerPixel: function(event)
26275 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26278 isApplied: function()
26280 return this.getGmapContext() == false ? false : true;
26283 getGmapContext: function()
26285 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26288 GMapContext: function()
26290 var position = new google.maps.LatLng(this.latitude, this.longitude);
26292 var _map = new google.maps.Map(this.el.dom, {
26295 mapTypeId: this.mapTypeId,
26296 mapTypeControl: this.mapTypeControl,
26297 disableDoubleClickZoom: this.disableDoubleClickZoom,
26298 scrollwheel: this.scrollwheel,
26299 streetViewControl: this.streetViewControl,
26300 locationName: this.locationName,
26301 draggable: this.draggable,
26302 enableAutocomplete: this.enableAutocomplete,
26303 enableReverseGeocode: this.enableReverseGeocode
26306 var _marker = new google.maps.Marker({
26307 position: position,
26309 title: this.markerTitle,
26310 draggable: this.draggable
26317 location: position,
26318 radius: this.radius,
26319 locationName: this.locationName,
26320 addressComponents: {
26321 formatted_address: null,
26322 addressLine1: null,
26323 addressLine2: null,
26325 streetNumber: null,
26329 stateOrProvince: null
26332 domContainer: this.el.dom,
26333 geodecoder: new google.maps.Geocoder()
26337 drawCircle: function(center, radius, options)
26339 if (this.gMapContext.circle != null) {
26340 this.gMapContext.circle.setMap(null);
26344 options = Roo.apply({}, options, {
26345 strokeColor: "#0000FF",
26346 strokeOpacity: .35,
26348 fillColor: "#0000FF",
26352 options.map = this.gMapContext.map;
26353 options.radius = radius;
26354 options.center = center;
26355 this.gMapContext.circle = new google.maps.Circle(options);
26356 return this.gMapContext.circle;
26362 setPosition: function(location)
26364 this.gMapContext.location = location;
26365 this.gMapContext.marker.setPosition(location);
26366 this.gMapContext.map.panTo(location);
26367 this.drawCircle(location, this.gMapContext.radius, {});
26371 if (this.gMapContext.settings.enableReverseGeocode) {
26372 this.gMapContext.geodecoder.geocode({
26373 latLng: this.gMapContext.location
26374 }, function(results, status) {
26376 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26377 _this.gMapContext.locationName = results[0].formatted_address;
26378 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26380 _this.fireEvent('positionchanged', this, location);
26387 this.fireEvent('positionchanged', this, location);
26392 google.maps.event.trigger(this.gMapContext.map, "resize");
26394 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26396 this.fireEvent('resize', this);
26399 setPositionByLatLng: function(latitude, longitude)
26401 this.setPosition(new google.maps.LatLng(latitude, longitude));
26404 getCurrentPosition: function()
26407 latitude: this.gMapContext.location.lat(),
26408 longitude: this.gMapContext.location.lng()
26412 getAddressName: function()
26414 return this.gMapContext.locationName;
26417 getAddressComponents: function()
26419 return this.gMapContext.addressComponents;
26422 address_component_from_google_geocode: function(address_components)
26426 for (var i = 0; i < address_components.length; i++) {
26427 var component = address_components[i];
26428 if (component.types.indexOf("postal_code") >= 0) {
26429 result.postalCode = component.short_name;
26430 } else if (component.types.indexOf("street_number") >= 0) {
26431 result.streetNumber = component.short_name;
26432 } else if (component.types.indexOf("route") >= 0) {
26433 result.streetName = component.short_name;
26434 } else if (component.types.indexOf("neighborhood") >= 0) {
26435 result.city = component.short_name;
26436 } else if (component.types.indexOf("locality") >= 0) {
26437 result.city = component.short_name;
26438 } else if (component.types.indexOf("sublocality") >= 0) {
26439 result.district = component.short_name;
26440 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26441 result.stateOrProvince = component.short_name;
26442 } else if (component.types.indexOf("country") >= 0) {
26443 result.country = component.short_name;
26447 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26448 result.addressLine2 = "";
26452 setZoomLevel: function(zoom)
26454 this.gMapContext.map.setZoom(zoom);
26467 this.fireEvent('show', this);
26478 this.fireEvent('hide', this);
26483 Roo.apply(Roo.bootstrap.LocationPicker, {
26485 OverlayView : function(map, options)
26487 options = options || {};
26501 * @class Roo.bootstrap.Alert
26502 * @extends Roo.bootstrap.Component
26503 * Bootstrap Alert class
26504 * @cfg {String} title The title of alert
26505 * @cfg {String} html The content of alert
26506 * @cfg {String} weight ( success | info | warning | danger )
26507 * @cfg {String} faicon font-awesomeicon
26510 * Create a new alert
26511 * @param {Object} config The config object
26515 Roo.bootstrap.Alert = function(config){
26516 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26520 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26527 getAutoCreate : function()
26536 cls : 'roo-alert-icon'
26541 cls : 'roo-alert-title',
26546 cls : 'roo-alert-text',
26553 cfg.cn[0].cls += ' fa ' + this.faicon;
26557 cfg.cls += ' alert-' + this.weight;
26563 initEvents: function()
26565 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26568 setTitle : function(str)
26570 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26573 setText : function(str)
26575 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26578 setWeight : function(weight)
26581 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26584 this.weight = weight;
26586 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26589 setIcon : function(icon)
26592 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26595 this.faicon = icon;
26597 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26618 * @class Roo.bootstrap.UploadCropbox
26619 * @extends Roo.bootstrap.Component
26620 * Bootstrap UploadCropbox class
26621 * @cfg {String} emptyText show when image has been loaded
26622 * @cfg {String} rotateNotify show when image too small to rotate
26623 * @cfg {Number} errorTimeout default 3000
26624 * @cfg {Number} minWidth default 300
26625 * @cfg {Number} minHeight default 300
26626 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26627 * @cfg {Boolean} isDocument (true|false) default false
26628 * @cfg {String} url action url
26629 * @cfg {String} paramName default 'imageUpload'
26630 * @cfg {String} method default POST
26631 * @cfg {Boolean} loadMask (true|false) default true
26632 * @cfg {Boolean} loadingText default 'Loading...'
26635 * Create a new UploadCropbox
26636 * @param {Object} config The config object
26639 Roo.bootstrap.UploadCropbox = function(config){
26640 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26644 * @event beforeselectfile
26645 * Fire before select file
26646 * @param {Roo.bootstrap.UploadCropbox} this
26648 "beforeselectfile" : true,
26651 * Fire after initEvent
26652 * @param {Roo.bootstrap.UploadCropbox} this
26657 * Fire after initEvent
26658 * @param {Roo.bootstrap.UploadCropbox} this
26659 * @param {String} data
26664 * Fire when preparing the file data
26665 * @param {Roo.bootstrap.UploadCropbox} this
26666 * @param {Object} file
26671 * Fire when get exception
26672 * @param {Roo.bootstrap.UploadCropbox} this
26673 * @param {XMLHttpRequest} xhr
26675 "exception" : true,
26677 * @event beforeloadcanvas
26678 * Fire before load the canvas
26679 * @param {Roo.bootstrap.UploadCropbox} this
26680 * @param {String} src
26682 "beforeloadcanvas" : true,
26685 * Fire when trash image
26686 * @param {Roo.bootstrap.UploadCropbox} this
26691 * Fire when download the image
26692 * @param {Roo.bootstrap.UploadCropbox} this
26696 * @event footerbuttonclick
26697 * Fire when footerbuttonclick
26698 * @param {Roo.bootstrap.UploadCropbox} this
26699 * @param {String} type
26701 "footerbuttonclick" : true,
26705 * @param {Roo.bootstrap.UploadCropbox} this
26710 * Fire when rotate the image
26711 * @param {Roo.bootstrap.UploadCropbox} this
26712 * @param {String} pos
26717 * Fire when inspect the file
26718 * @param {Roo.bootstrap.UploadCropbox} this
26719 * @param {Object} file
26724 * Fire when xhr upload the file
26725 * @param {Roo.bootstrap.UploadCropbox} this
26726 * @param {Object} data
26731 * Fire when arrange the file data
26732 * @param {Roo.bootstrap.UploadCropbox} this
26733 * @param {Object} formData
26738 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26741 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26743 emptyText : 'Click to upload image',
26744 rotateNotify : 'Image is too small to rotate',
26745 errorTimeout : 3000,
26759 cropType : 'image/jpeg',
26761 canvasLoaded : false,
26762 isDocument : false,
26764 paramName : 'imageUpload',
26766 loadingText : 'Loading...',
26769 getAutoCreate : function()
26773 cls : 'roo-upload-cropbox',
26777 cls : 'roo-upload-cropbox-selector',
26782 cls : 'roo-upload-cropbox-body',
26783 style : 'cursor:pointer',
26787 cls : 'roo-upload-cropbox-preview'
26791 cls : 'roo-upload-cropbox-thumb'
26795 cls : 'roo-upload-cropbox-empty-notify',
26796 html : this.emptyText
26800 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26801 html : this.rotateNotify
26807 cls : 'roo-upload-cropbox-footer',
26810 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26820 onRender : function(ct, position)
26822 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26824 if (this.buttons.length) {
26826 Roo.each(this.buttons, function(bb) {
26828 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26830 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26836 this.maskEl = this.el;
26840 initEvents : function()
26842 this.urlAPI = (window.createObjectURL && window) ||
26843 (window.URL && URL.revokeObjectURL && URL) ||
26844 (window.webkitURL && webkitURL);
26846 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26847 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26849 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26850 this.selectorEl.hide();
26852 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26853 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26855 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26856 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26857 this.thumbEl.hide();
26859 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26860 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26862 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26863 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26864 this.errorEl.hide();
26866 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26867 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26868 this.footerEl.hide();
26870 this.setThumbBoxSize();
26876 this.fireEvent('initial', this);
26883 window.addEventListener("resize", function() { _this.resize(); } );
26885 this.bodyEl.on('click', this.beforeSelectFile, this);
26888 this.bodyEl.on('touchstart', this.onTouchStart, this);
26889 this.bodyEl.on('touchmove', this.onTouchMove, this);
26890 this.bodyEl.on('touchend', this.onTouchEnd, this);
26894 this.bodyEl.on('mousedown', this.onMouseDown, this);
26895 this.bodyEl.on('mousemove', this.onMouseMove, this);
26896 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26897 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26898 Roo.get(document).on('mouseup', this.onMouseUp, this);
26901 this.selectorEl.on('change', this.onFileSelected, this);
26907 this.baseScale = 1;
26909 this.baseRotate = 1;
26910 this.dragable = false;
26911 this.pinching = false;
26914 this.cropData = false;
26915 this.notifyEl.dom.innerHTML = this.emptyText;
26917 this.selectorEl.dom.value = '';
26921 resize : function()
26923 if(this.fireEvent('resize', this) != false){
26924 this.setThumbBoxPosition();
26925 this.setCanvasPosition();
26929 onFooterButtonClick : function(e, el, o, type)
26932 case 'rotate-left' :
26933 this.onRotateLeft(e);
26935 case 'rotate-right' :
26936 this.onRotateRight(e);
26939 this.beforeSelectFile(e);
26954 this.fireEvent('footerbuttonclick', this, type);
26957 beforeSelectFile : function(e)
26959 e.preventDefault();
26961 if(this.fireEvent('beforeselectfile', this) != false){
26962 this.selectorEl.dom.click();
26966 onFileSelected : function(e)
26968 e.preventDefault();
26970 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26974 var file = this.selectorEl.dom.files[0];
26976 if(this.fireEvent('inspect', this, file) != false){
26977 this.prepare(file);
26982 trash : function(e)
26984 this.fireEvent('trash', this);
26987 download : function(e)
26989 this.fireEvent('download', this);
26992 loadCanvas : function(src)
26994 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26998 this.imageEl = document.createElement('img');
27002 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27004 this.imageEl.src = src;
27008 onLoadCanvas : function()
27010 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27011 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27013 this.bodyEl.un('click', this.beforeSelectFile, this);
27015 this.notifyEl.hide();
27016 this.thumbEl.show();
27017 this.footerEl.show();
27019 this.baseRotateLevel();
27021 if(this.isDocument){
27022 this.setThumbBoxSize();
27025 this.setThumbBoxPosition();
27027 this.baseScaleLevel();
27033 this.canvasLoaded = true;
27036 this.maskEl.unmask();
27041 setCanvasPosition : function()
27043 if(!this.canvasEl){
27047 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27048 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27050 this.previewEl.setLeft(pw);
27051 this.previewEl.setTop(ph);
27055 onMouseDown : function(e)
27059 this.dragable = true;
27060 this.pinching = false;
27062 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27063 this.dragable = false;
27067 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27068 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27072 onMouseMove : function(e)
27076 if(!this.canvasLoaded){
27080 if (!this.dragable){
27084 var minX = Math.ceil(this.thumbEl.getLeft(true));
27085 var minY = Math.ceil(this.thumbEl.getTop(true));
27087 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27088 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27090 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27091 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27093 x = x - this.mouseX;
27094 y = y - this.mouseY;
27096 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27097 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27099 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27100 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27102 this.previewEl.setLeft(bgX);
27103 this.previewEl.setTop(bgY);
27105 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27106 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27109 onMouseUp : function(e)
27113 this.dragable = false;
27116 onMouseWheel : function(e)
27120 this.startScale = this.scale;
27122 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27124 if(!this.zoomable()){
27125 this.scale = this.startScale;
27134 zoomable : function()
27136 var minScale = this.thumbEl.getWidth() / this.minWidth;
27138 if(this.minWidth < this.minHeight){
27139 minScale = this.thumbEl.getHeight() / this.minHeight;
27142 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27143 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27147 (this.rotate == 0 || this.rotate == 180) &&
27149 width > this.imageEl.OriginWidth ||
27150 height > this.imageEl.OriginHeight ||
27151 (width < this.minWidth && height < this.minHeight)
27159 (this.rotate == 90 || this.rotate == 270) &&
27161 width > this.imageEl.OriginWidth ||
27162 height > this.imageEl.OriginHeight ||
27163 (width < this.minHeight && height < this.minWidth)
27170 !this.isDocument &&
27171 (this.rotate == 0 || this.rotate == 180) &&
27173 width < this.minWidth ||
27174 width > this.imageEl.OriginWidth ||
27175 height < this.minHeight ||
27176 height > this.imageEl.OriginHeight
27183 !this.isDocument &&
27184 (this.rotate == 90 || this.rotate == 270) &&
27186 width < this.minHeight ||
27187 width > this.imageEl.OriginWidth ||
27188 height < this.minWidth ||
27189 height > this.imageEl.OriginHeight
27199 onRotateLeft : function(e)
27201 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27203 var minScale = this.thumbEl.getWidth() / this.minWidth;
27205 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27206 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27208 this.startScale = this.scale;
27210 while (this.getScaleLevel() < minScale){
27212 this.scale = this.scale + 1;
27214 if(!this.zoomable()){
27219 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27220 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27225 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27232 this.scale = this.startScale;
27234 this.onRotateFail();
27239 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27241 if(this.isDocument){
27242 this.setThumbBoxSize();
27243 this.setThumbBoxPosition();
27244 this.setCanvasPosition();
27249 this.fireEvent('rotate', this, 'left');
27253 onRotateRight : function(e)
27255 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27257 var minScale = this.thumbEl.getWidth() / this.minWidth;
27259 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27260 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27262 this.startScale = this.scale;
27264 while (this.getScaleLevel() < minScale){
27266 this.scale = this.scale + 1;
27268 if(!this.zoomable()){
27273 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27274 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27279 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27286 this.scale = this.startScale;
27288 this.onRotateFail();
27293 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27295 if(this.isDocument){
27296 this.setThumbBoxSize();
27297 this.setThumbBoxPosition();
27298 this.setCanvasPosition();
27303 this.fireEvent('rotate', this, 'right');
27306 onRotateFail : function()
27308 this.errorEl.show(true);
27312 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27317 this.previewEl.dom.innerHTML = '';
27319 var canvasEl = document.createElement("canvas");
27321 var contextEl = canvasEl.getContext("2d");
27323 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27324 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27325 var center = this.imageEl.OriginWidth / 2;
27327 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27328 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27329 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27330 center = this.imageEl.OriginHeight / 2;
27333 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27335 contextEl.translate(center, center);
27336 contextEl.rotate(this.rotate * Math.PI / 180);
27338 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27340 this.canvasEl = document.createElement("canvas");
27342 this.contextEl = this.canvasEl.getContext("2d");
27344 switch (this.rotate) {
27347 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27348 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27350 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27355 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27356 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27358 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27359 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);
27363 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27368 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27369 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27371 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27372 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);
27376 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);
27381 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27382 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27384 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27385 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27389 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);
27396 this.previewEl.appendChild(this.canvasEl);
27398 this.setCanvasPosition();
27403 if(!this.canvasLoaded){
27407 var imageCanvas = document.createElement("canvas");
27409 var imageContext = imageCanvas.getContext("2d");
27411 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27412 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27414 var center = imageCanvas.width / 2;
27416 imageContext.translate(center, center);
27418 imageContext.rotate(this.rotate * Math.PI / 180);
27420 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27422 var canvas = document.createElement("canvas");
27424 var context = canvas.getContext("2d");
27426 canvas.width = this.minWidth;
27427 canvas.height = this.minHeight;
27429 switch (this.rotate) {
27432 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27433 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27435 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27436 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27438 var targetWidth = this.minWidth - 2 * x;
27439 var targetHeight = this.minHeight - 2 * y;
27443 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27444 scale = targetWidth / width;
27447 if(x > 0 && y == 0){
27448 scale = targetHeight / height;
27451 if(x > 0 && y > 0){
27452 scale = targetWidth / width;
27454 if(width < height){
27455 scale = targetHeight / height;
27459 context.scale(scale, scale);
27461 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27462 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27464 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27465 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27467 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27472 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27473 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27475 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27476 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27478 var targetWidth = this.minWidth - 2 * x;
27479 var targetHeight = this.minHeight - 2 * y;
27483 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27484 scale = targetWidth / width;
27487 if(x > 0 && y == 0){
27488 scale = targetHeight / height;
27491 if(x > 0 && y > 0){
27492 scale = targetWidth / width;
27494 if(width < height){
27495 scale = targetHeight / height;
27499 context.scale(scale, scale);
27501 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27502 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27504 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27505 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27507 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27509 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27514 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27515 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27517 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27518 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27520 var targetWidth = this.minWidth - 2 * x;
27521 var targetHeight = this.minHeight - 2 * y;
27525 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27526 scale = targetWidth / width;
27529 if(x > 0 && y == 0){
27530 scale = targetHeight / height;
27533 if(x > 0 && y > 0){
27534 scale = targetWidth / width;
27536 if(width < height){
27537 scale = targetHeight / height;
27541 context.scale(scale, scale);
27543 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27544 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27546 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27547 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27549 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27550 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27552 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27557 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27558 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27560 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27561 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27563 var targetWidth = this.minWidth - 2 * x;
27564 var targetHeight = this.minHeight - 2 * y;
27568 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27569 scale = targetWidth / width;
27572 if(x > 0 && y == 0){
27573 scale = targetHeight / height;
27576 if(x > 0 && y > 0){
27577 scale = targetWidth / width;
27579 if(width < height){
27580 scale = targetHeight / height;
27584 context.scale(scale, scale);
27586 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27587 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27589 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27590 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27592 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27594 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27601 this.cropData = canvas.toDataURL(this.cropType);
27603 if(this.fireEvent('crop', this, this.cropData) !== false){
27604 this.process(this.file, this.cropData);
27611 setThumbBoxSize : function()
27615 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27616 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27617 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27619 this.minWidth = width;
27620 this.minHeight = height;
27622 if(this.rotate == 90 || this.rotate == 270){
27623 this.minWidth = height;
27624 this.minHeight = width;
27629 width = Math.ceil(this.minWidth * height / this.minHeight);
27631 if(this.minWidth > this.minHeight){
27633 height = Math.ceil(this.minHeight * width / this.minWidth);
27636 this.thumbEl.setStyle({
27637 width : width + 'px',
27638 height : height + 'px'
27645 setThumbBoxPosition : function()
27647 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27648 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27650 this.thumbEl.setLeft(x);
27651 this.thumbEl.setTop(y);
27655 baseRotateLevel : function()
27657 this.baseRotate = 1;
27660 typeof(this.exif) != 'undefined' &&
27661 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27662 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27664 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27667 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27671 baseScaleLevel : function()
27675 if(this.isDocument){
27677 if(this.baseRotate == 6 || this.baseRotate == 8){
27679 height = this.thumbEl.getHeight();
27680 this.baseScale = height / this.imageEl.OriginWidth;
27682 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27683 width = this.thumbEl.getWidth();
27684 this.baseScale = width / this.imageEl.OriginHeight;
27690 height = this.thumbEl.getHeight();
27691 this.baseScale = height / this.imageEl.OriginHeight;
27693 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27694 width = this.thumbEl.getWidth();
27695 this.baseScale = width / this.imageEl.OriginWidth;
27701 if(this.baseRotate == 6 || this.baseRotate == 8){
27703 width = this.thumbEl.getHeight();
27704 this.baseScale = width / this.imageEl.OriginHeight;
27706 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27707 height = this.thumbEl.getWidth();
27708 this.baseScale = height / this.imageEl.OriginHeight;
27711 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27712 height = this.thumbEl.getWidth();
27713 this.baseScale = height / this.imageEl.OriginHeight;
27715 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27716 width = this.thumbEl.getHeight();
27717 this.baseScale = width / this.imageEl.OriginWidth;
27724 width = this.thumbEl.getWidth();
27725 this.baseScale = width / this.imageEl.OriginWidth;
27727 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27728 height = this.thumbEl.getHeight();
27729 this.baseScale = height / this.imageEl.OriginHeight;
27732 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27734 height = this.thumbEl.getHeight();
27735 this.baseScale = height / this.imageEl.OriginHeight;
27737 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27738 width = this.thumbEl.getWidth();
27739 this.baseScale = width / this.imageEl.OriginWidth;
27747 getScaleLevel : function()
27749 return this.baseScale * Math.pow(1.1, this.scale);
27752 onTouchStart : function(e)
27754 if(!this.canvasLoaded){
27755 this.beforeSelectFile(e);
27759 var touches = e.browserEvent.touches;
27765 if(touches.length == 1){
27766 this.onMouseDown(e);
27770 if(touches.length != 2){
27776 for(var i = 0, finger; finger = touches[i]; i++){
27777 coords.push(finger.pageX, finger.pageY);
27780 var x = Math.pow(coords[0] - coords[2], 2);
27781 var y = Math.pow(coords[1] - coords[3], 2);
27783 this.startDistance = Math.sqrt(x + y);
27785 this.startScale = this.scale;
27787 this.pinching = true;
27788 this.dragable = false;
27792 onTouchMove : function(e)
27794 if(!this.pinching && !this.dragable){
27798 var touches = e.browserEvent.touches;
27805 this.onMouseMove(e);
27811 for(var i = 0, finger; finger = touches[i]; i++){
27812 coords.push(finger.pageX, finger.pageY);
27815 var x = Math.pow(coords[0] - coords[2], 2);
27816 var y = Math.pow(coords[1] - coords[3], 2);
27818 this.endDistance = Math.sqrt(x + y);
27820 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27822 if(!this.zoomable()){
27823 this.scale = this.startScale;
27831 onTouchEnd : function(e)
27833 this.pinching = false;
27834 this.dragable = false;
27838 process : function(file, crop)
27841 this.maskEl.mask(this.loadingText);
27844 this.xhr = new XMLHttpRequest();
27846 file.xhr = this.xhr;
27848 this.xhr.open(this.method, this.url, true);
27851 "Accept": "application/json",
27852 "Cache-Control": "no-cache",
27853 "X-Requested-With": "XMLHttpRequest"
27856 for (var headerName in headers) {
27857 var headerValue = headers[headerName];
27859 this.xhr.setRequestHeader(headerName, headerValue);
27865 this.xhr.onload = function()
27867 _this.xhrOnLoad(_this.xhr);
27870 this.xhr.onerror = function()
27872 _this.xhrOnError(_this.xhr);
27875 var formData = new FormData();
27877 formData.append('returnHTML', 'NO');
27880 formData.append('crop', crop);
27883 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27884 formData.append(this.paramName, file, file.name);
27887 if(typeof(file.filename) != 'undefined'){
27888 formData.append('filename', file.filename);
27891 if(typeof(file.mimetype) != 'undefined'){
27892 formData.append('mimetype', file.mimetype);
27895 if(this.fireEvent('arrange', this, formData) != false){
27896 this.xhr.send(formData);
27900 xhrOnLoad : function(xhr)
27903 this.maskEl.unmask();
27906 if (xhr.readyState !== 4) {
27907 this.fireEvent('exception', this, xhr);
27911 var response = Roo.decode(xhr.responseText);
27913 if(!response.success){
27914 this.fireEvent('exception', this, xhr);
27918 var response = Roo.decode(xhr.responseText);
27920 this.fireEvent('upload', this, response);
27924 xhrOnError : function()
27927 this.maskEl.unmask();
27930 Roo.log('xhr on error');
27932 var response = Roo.decode(xhr.responseText);
27938 prepare : function(file)
27941 this.maskEl.mask(this.loadingText);
27947 if(typeof(file) === 'string'){
27948 this.loadCanvas(file);
27952 if(!file || !this.urlAPI){
27957 this.cropType = file.type;
27961 if(this.fireEvent('prepare', this, this.file) != false){
27963 var reader = new FileReader();
27965 reader.onload = function (e) {
27966 if (e.target.error) {
27967 Roo.log(e.target.error);
27971 var buffer = e.target.result,
27972 dataView = new DataView(buffer),
27974 maxOffset = dataView.byteLength - 4,
27978 if (dataView.getUint16(0) === 0xffd8) {
27979 while (offset < maxOffset) {
27980 markerBytes = dataView.getUint16(offset);
27982 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27983 markerLength = dataView.getUint16(offset + 2) + 2;
27984 if (offset + markerLength > dataView.byteLength) {
27985 Roo.log('Invalid meta data: Invalid segment size.');
27989 if(markerBytes == 0xffe1){
27990 _this.parseExifData(
27997 offset += markerLength;
28007 var url = _this.urlAPI.createObjectURL(_this.file);
28009 _this.loadCanvas(url);
28014 reader.readAsArrayBuffer(this.file);
28020 parseExifData : function(dataView, offset, length)
28022 var tiffOffset = offset + 10,
28026 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28027 // No Exif data, might be XMP data instead
28031 // Check for the ASCII code for "Exif" (0x45786966):
28032 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28033 // No Exif data, might be XMP data instead
28036 if (tiffOffset + 8 > dataView.byteLength) {
28037 Roo.log('Invalid Exif data: Invalid segment size.');
28040 // Check for the two null bytes:
28041 if (dataView.getUint16(offset + 8) !== 0x0000) {
28042 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28045 // Check the byte alignment:
28046 switch (dataView.getUint16(tiffOffset)) {
28048 littleEndian = true;
28051 littleEndian = false;
28054 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28057 // Check for the TIFF tag marker (0x002A):
28058 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28059 Roo.log('Invalid Exif data: Missing TIFF marker.');
28062 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28063 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28065 this.parseExifTags(
28068 tiffOffset + dirOffset,
28073 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28078 if (dirOffset + 6 > dataView.byteLength) {
28079 Roo.log('Invalid Exif data: Invalid directory offset.');
28082 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28083 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28084 if (dirEndOffset + 4 > dataView.byteLength) {
28085 Roo.log('Invalid Exif data: Invalid directory size.');
28088 for (i = 0; i < tagsNumber; i += 1) {
28092 dirOffset + 2 + 12 * i, // tag offset
28096 // Return the offset to the next directory:
28097 return dataView.getUint32(dirEndOffset, littleEndian);
28100 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28102 var tag = dataView.getUint16(offset, littleEndian);
28104 this.exif[tag] = this.getExifValue(
28108 dataView.getUint16(offset + 2, littleEndian), // tag type
28109 dataView.getUint32(offset + 4, littleEndian), // tag length
28114 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28116 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28125 Roo.log('Invalid Exif data: Invalid tag type.');
28129 tagSize = tagType.size * length;
28130 // Determine if the value is contained in the dataOffset bytes,
28131 // or if the value at the dataOffset is a pointer to the actual data:
28132 dataOffset = tagSize > 4 ?
28133 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28134 if (dataOffset + tagSize > dataView.byteLength) {
28135 Roo.log('Invalid Exif data: Invalid data offset.');
28138 if (length === 1) {
28139 return tagType.getValue(dataView, dataOffset, littleEndian);
28142 for (i = 0; i < length; i += 1) {
28143 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28146 if (tagType.ascii) {
28148 // Concatenate the chars:
28149 for (i = 0; i < values.length; i += 1) {
28151 // Ignore the terminating NULL byte(s):
28152 if (c === '\u0000') {
28164 Roo.apply(Roo.bootstrap.UploadCropbox, {
28166 'Orientation': 0x0112
28170 1: 0, //'top-left',
28172 3: 180, //'bottom-right',
28173 // 4: 'bottom-left',
28175 6: 90, //'right-top',
28176 // 7: 'right-bottom',
28177 8: 270 //'left-bottom'
28181 // byte, 8-bit unsigned int:
28183 getValue: function (dataView, dataOffset) {
28184 return dataView.getUint8(dataOffset);
28188 // ascii, 8-bit byte:
28190 getValue: function (dataView, dataOffset) {
28191 return String.fromCharCode(dataView.getUint8(dataOffset));
28196 // short, 16 bit int:
28198 getValue: function (dataView, dataOffset, littleEndian) {
28199 return dataView.getUint16(dataOffset, littleEndian);
28203 // long, 32 bit int:
28205 getValue: function (dataView, dataOffset, littleEndian) {
28206 return dataView.getUint32(dataOffset, littleEndian);
28210 // rational = two long values, first is numerator, second is denominator:
28212 getValue: function (dataView, dataOffset, littleEndian) {
28213 return dataView.getUint32(dataOffset, littleEndian) /
28214 dataView.getUint32(dataOffset + 4, littleEndian);
28218 // slong, 32 bit signed int:
28220 getValue: function (dataView, dataOffset, littleEndian) {
28221 return dataView.getInt32(dataOffset, littleEndian);
28225 // srational, two slongs, first is numerator, second is denominator:
28227 getValue: function (dataView, dataOffset, littleEndian) {
28228 return dataView.getInt32(dataOffset, littleEndian) /
28229 dataView.getInt32(dataOffset + 4, littleEndian);
28239 cls : 'btn-group roo-upload-cropbox-rotate-left',
28240 action : 'rotate-left',
28244 cls : 'btn btn-default',
28245 html : '<i class="fa fa-undo"></i>'
28251 cls : 'btn-group roo-upload-cropbox-picture',
28252 action : 'picture',
28256 cls : 'btn btn-default',
28257 html : '<i class="fa fa-picture-o"></i>'
28263 cls : 'btn-group roo-upload-cropbox-rotate-right',
28264 action : 'rotate-right',
28268 cls : 'btn btn-default',
28269 html : '<i class="fa fa-repeat"></i>'
28277 cls : 'btn-group roo-upload-cropbox-rotate-left',
28278 action : 'rotate-left',
28282 cls : 'btn btn-default',
28283 html : '<i class="fa fa-undo"></i>'
28289 cls : 'btn-group roo-upload-cropbox-download',
28290 action : 'download',
28294 cls : 'btn btn-default',
28295 html : '<i class="fa fa-download"></i>'
28301 cls : 'btn-group roo-upload-cropbox-crop',
28306 cls : 'btn btn-default',
28307 html : '<i class="fa fa-crop"></i>'
28313 cls : 'btn-group roo-upload-cropbox-trash',
28318 cls : 'btn btn-default',
28319 html : '<i class="fa fa-trash"></i>'
28325 cls : 'btn-group roo-upload-cropbox-rotate-right',
28326 action : 'rotate-right',
28330 cls : 'btn btn-default',
28331 html : '<i class="fa fa-repeat"></i>'
28339 cls : 'btn-group roo-upload-cropbox-rotate-left',
28340 action : 'rotate-left',
28344 cls : 'btn btn-default',
28345 html : '<i class="fa fa-undo"></i>'
28351 cls : 'btn-group roo-upload-cropbox-rotate-right',
28352 action : 'rotate-right',
28356 cls : 'btn btn-default',
28357 html : '<i class="fa fa-repeat"></i>'
28370 * @class Roo.bootstrap.DocumentManager
28371 * @extends Roo.bootstrap.Component
28372 * Bootstrap DocumentManager class
28373 * @cfg {String} paramName default 'imageUpload'
28374 * @cfg {String} toolTipName default 'filename'
28375 * @cfg {String} method default POST
28376 * @cfg {String} url action url
28377 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28378 * @cfg {Boolean} multiple multiple upload default true
28379 * @cfg {Number} thumbSize default 300
28380 * @cfg {String} fieldLabel
28381 * @cfg {Number} labelWidth default 4
28382 * @cfg {String} labelAlign (left|top) default left
28383 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28384 * @cfg {Number} labellg set the width of label (1-12)
28385 * @cfg {Number} labelmd set the width of label (1-12)
28386 * @cfg {Number} labelsm set the width of label (1-12)
28387 * @cfg {Number} labelxs set the width of label (1-12)
28390 * Create a new DocumentManager
28391 * @param {Object} config The config object
28394 Roo.bootstrap.DocumentManager = function(config){
28395 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28398 this.delegates = [];
28403 * Fire when initial the DocumentManager
28404 * @param {Roo.bootstrap.DocumentManager} this
28409 * inspect selected file
28410 * @param {Roo.bootstrap.DocumentManager} this
28411 * @param {File} file
28416 * Fire when xhr load exception
28417 * @param {Roo.bootstrap.DocumentManager} this
28418 * @param {XMLHttpRequest} xhr
28420 "exception" : true,
28422 * @event afterupload
28423 * Fire when xhr load exception
28424 * @param {Roo.bootstrap.DocumentManager} this
28425 * @param {XMLHttpRequest} xhr
28427 "afterupload" : true,
28430 * prepare the form data
28431 * @param {Roo.bootstrap.DocumentManager} this
28432 * @param {Object} formData
28437 * Fire when remove the file
28438 * @param {Roo.bootstrap.DocumentManager} this
28439 * @param {Object} file
28444 * Fire after refresh the file
28445 * @param {Roo.bootstrap.DocumentManager} this
28450 * Fire after click the image
28451 * @param {Roo.bootstrap.DocumentManager} this
28452 * @param {Object} file
28457 * Fire when upload a image and editable set to true
28458 * @param {Roo.bootstrap.DocumentManager} this
28459 * @param {Object} file
28463 * @event beforeselectfile
28464 * Fire before select file
28465 * @param {Roo.bootstrap.DocumentManager} this
28467 "beforeselectfile" : true,
28470 * Fire before process file
28471 * @param {Roo.bootstrap.DocumentManager} this
28472 * @param {Object} file
28476 * @event previewrendered
28477 * Fire when preview rendered
28478 * @param {Roo.bootstrap.DocumentManager} this
28479 * @param {Object} file
28481 "previewrendered" : true
28486 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28495 paramName : 'imageUpload',
28496 toolTipName : 'filename',
28499 labelAlign : 'left',
28509 getAutoCreate : function()
28511 var managerWidget = {
28513 cls : 'roo-document-manager',
28517 cls : 'roo-document-manager-selector',
28522 cls : 'roo-document-manager-uploader',
28526 cls : 'roo-document-manager-upload-btn',
28527 html : '<i class="fa fa-plus"></i>'
28538 cls : 'column col-md-12',
28543 if(this.fieldLabel.length){
28548 cls : 'column col-md-12',
28549 html : this.fieldLabel
28553 cls : 'column col-md-12',
28558 if(this.labelAlign == 'left'){
28563 html : this.fieldLabel
28572 if(this.labelWidth > 12){
28573 content[0].style = "width: " + this.labelWidth + 'px';
28576 if(this.labelWidth < 13 && this.labelmd == 0){
28577 this.labelmd = this.labelWidth;
28580 if(this.labellg > 0){
28581 content[0].cls += ' col-lg-' + this.labellg;
28582 content[1].cls += ' col-lg-' + (12 - this.labellg);
28585 if(this.labelmd > 0){
28586 content[0].cls += ' col-md-' + this.labelmd;
28587 content[1].cls += ' col-md-' + (12 - this.labelmd);
28590 if(this.labelsm > 0){
28591 content[0].cls += ' col-sm-' + this.labelsm;
28592 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28595 if(this.labelxs > 0){
28596 content[0].cls += ' col-xs-' + this.labelxs;
28597 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28605 cls : 'row clearfix',
28613 initEvents : function()
28615 this.managerEl = this.el.select('.roo-document-manager', true).first();
28616 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28618 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28619 this.selectorEl.hide();
28622 this.selectorEl.attr('multiple', 'multiple');
28625 this.selectorEl.on('change', this.onFileSelected, this);
28627 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28628 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28630 this.uploader.on('click', this.onUploaderClick, this);
28632 this.renderProgressDialog();
28636 window.addEventListener("resize", function() { _this.refresh(); } );
28638 this.fireEvent('initial', this);
28641 renderProgressDialog : function()
28645 this.progressDialog = new Roo.bootstrap.Modal({
28646 cls : 'roo-document-manager-progress-dialog',
28647 allow_close : false,
28657 btnclick : function() {
28658 _this.uploadCancel();
28664 this.progressDialog.render(Roo.get(document.body));
28666 this.progress = new Roo.bootstrap.Progress({
28667 cls : 'roo-document-manager-progress',
28672 this.progress.render(this.progressDialog.getChildContainer());
28674 this.progressBar = new Roo.bootstrap.ProgressBar({
28675 cls : 'roo-document-manager-progress-bar',
28678 aria_valuemax : 12,
28682 this.progressBar.render(this.progress.getChildContainer());
28685 onUploaderClick : function(e)
28687 e.preventDefault();
28689 if(this.fireEvent('beforeselectfile', this) != false){
28690 this.selectorEl.dom.click();
28695 onFileSelected : function(e)
28697 e.preventDefault();
28699 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28703 Roo.each(this.selectorEl.dom.files, function(file){
28704 if(this.fireEvent('inspect', this, file) != false){
28705 this.files.push(file);
28715 this.selectorEl.dom.value = '';
28717 if(!this.files || !this.files.length){
28721 if(this.boxes > 0 && this.files.length > this.boxes){
28722 this.files = this.files.slice(0, this.boxes);
28725 this.uploader.show();
28727 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28728 this.uploader.hide();
28737 Roo.each(this.files, function(file){
28739 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28740 var f = this.renderPreview(file);
28745 if(file.type.indexOf('image') != -1){
28746 this.delegates.push(
28748 _this.process(file);
28749 }).createDelegate(this)
28757 _this.process(file);
28758 }).createDelegate(this)
28763 this.files = files;
28765 this.delegates = this.delegates.concat(docs);
28767 if(!this.delegates.length){
28772 this.progressBar.aria_valuemax = this.delegates.length;
28779 arrange : function()
28781 if(!this.delegates.length){
28782 this.progressDialog.hide();
28787 var delegate = this.delegates.shift();
28789 this.progressDialog.show();
28791 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28793 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28798 refresh : function()
28800 this.uploader.show();
28802 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28803 this.uploader.hide();
28806 Roo.isTouch ? this.closable(false) : this.closable(true);
28808 this.fireEvent('refresh', this);
28811 onRemove : function(e, el, o)
28813 e.preventDefault();
28815 this.fireEvent('remove', this, o);
28819 remove : function(o)
28823 Roo.each(this.files, function(file){
28824 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28833 this.files = files;
28840 Roo.each(this.files, function(file){
28845 file.target.remove();
28854 onClick : function(e, el, o)
28856 e.preventDefault();
28858 this.fireEvent('click', this, o);
28862 closable : function(closable)
28864 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28866 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28878 xhrOnLoad : function(xhr)
28880 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28884 if (xhr.readyState !== 4) {
28886 this.fireEvent('exception', this, xhr);
28890 var response = Roo.decode(xhr.responseText);
28892 if(!response.success){
28894 this.fireEvent('exception', this, xhr);
28898 var file = this.renderPreview(response.data);
28900 this.files.push(file);
28904 this.fireEvent('afterupload', this, xhr);
28908 xhrOnError : function(xhr)
28910 Roo.log('xhr on error');
28912 var response = Roo.decode(xhr.responseText);
28919 process : function(file)
28921 if(this.fireEvent('process', this, file) !== false){
28922 if(this.editable && file.type.indexOf('image') != -1){
28923 this.fireEvent('edit', this, file);
28927 this.uploadStart(file, false);
28934 uploadStart : function(file, crop)
28936 this.xhr = new XMLHttpRequest();
28938 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28943 file.xhr = this.xhr;
28945 this.managerEl.createChild({
28947 cls : 'roo-document-manager-loading',
28951 tooltip : file.name,
28952 cls : 'roo-document-manager-thumb',
28953 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28959 this.xhr.open(this.method, this.url, true);
28962 "Accept": "application/json",
28963 "Cache-Control": "no-cache",
28964 "X-Requested-With": "XMLHttpRequest"
28967 for (var headerName in headers) {
28968 var headerValue = headers[headerName];
28970 this.xhr.setRequestHeader(headerName, headerValue);
28976 this.xhr.onload = function()
28978 _this.xhrOnLoad(_this.xhr);
28981 this.xhr.onerror = function()
28983 _this.xhrOnError(_this.xhr);
28986 var formData = new FormData();
28988 formData.append('returnHTML', 'NO');
28991 formData.append('crop', crop);
28994 formData.append(this.paramName, file, file.name);
29001 if(this.fireEvent('prepare', this, formData, options) != false){
29003 if(options.manually){
29007 this.xhr.send(formData);
29011 this.uploadCancel();
29014 uploadCancel : function()
29020 this.delegates = [];
29022 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29029 renderPreview : function(file)
29031 if(typeof(file.target) != 'undefined' && file.target){
29035 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29037 var previewEl = this.managerEl.createChild({
29039 cls : 'roo-document-manager-preview',
29043 tooltip : file[this.toolTipName],
29044 cls : 'roo-document-manager-thumb',
29045 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29050 html : '<i class="fa fa-times-circle"></i>'
29055 var close = previewEl.select('button.close', true).first();
29057 close.on('click', this.onRemove, this, file);
29059 file.target = previewEl;
29061 var image = previewEl.select('img', true).first();
29065 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29067 image.on('click', this.onClick, this, file);
29069 this.fireEvent('previewrendered', this, file);
29075 onPreviewLoad : function(file, image)
29077 if(typeof(file.target) == 'undefined' || !file.target){
29081 var width = image.dom.naturalWidth || image.dom.width;
29082 var height = image.dom.naturalHeight || image.dom.height;
29084 if(width > height){
29085 file.target.addClass('wide');
29089 file.target.addClass('tall');
29094 uploadFromSource : function(file, crop)
29096 this.xhr = new XMLHttpRequest();
29098 this.managerEl.createChild({
29100 cls : 'roo-document-manager-loading',
29104 tooltip : file.name,
29105 cls : 'roo-document-manager-thumb',
29106 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29112 this.xhr.open(this.method, this.url, true);
29115 "Accept": "application/json",
29116 "Cache-Control": "no-cache",
29117 "X-Requested-With": "XMLHttpRequest"
29120 for (var headerName in headers) {
29121 var headerValue = headers[headerName];
29123 this.xhr.setRequestHeader(headerName, headerValue);
29129 this.xhr.onload = function()
29131 _this.xhrOnLoad(_this.xhr);
29134 this.xhr.onerror = function()
29136 _this.xhrOnError(_this.xhr);
29139 var formData = new FormData();
29141 formData.append('returnHTML', 'NO');
29143 formData.append('crop', crop);
29145 if(typeof(file.filename) != 'undefined'){
29146 formData.append('filename', file.filename);
29149 if(typeof(file.mimetype) != 'undefined'){
29150 formData.append('mimetype', file.mimetype);
29155 if(this.fireEvent('prepare', this, formData) != false){
29156 this.xhr.send(formData);
29166 * @class Roo.bootstrap.DocumentViewer
29167 * @extends Roo.bootstrap.Component
29168 * Bootstrap DocumentViewer class
29169 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29170 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29173 * Create a new DocumentViewer
29174 * @param {Object} config The config object
29177 Roo.bootstrap.DocumentViewer = function(config){
29178 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29183 * Fire after initEvent
29184 * @param {Roo.bootstrap.DocumentViewer} this
29190 * @param {Roo.bootstrap.DocumentViewer} this
29195 * Fire after download button
29196 * @param {Roo.bootstrap.DocumentViewer} this
29201 * Fire after trash button
29202 * @param {Roo.bootstrap.DocumentViewer} this
29209 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29211 showDownload : true,
29215 getAutoCreate : function()
29219 cls : 'roo-document-viewer',
29223 cls : 'roo-document-viewer-body',
29227 cls : 'roo-document-viewer-thumb',
29231 cls : 'roo-document-viewer-image'
29239 cls : 'roo-document-viewer-footer',
29242 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29246 cls : 'btn-group roo-document-viewer-download',
29250 cls : 'btn btn-default',
29251 html : '<i class="fa fa-download"></i>'
29257 cls : 'btn-group roo-document-viewer-trash',
29261 cls : 'btn btn-default',
29262 html : '<i class="fa fa-trash"></i>'
29275 initEvents : function()
29277 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29278 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29280 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29281 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29283 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29284 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29286 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29287 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29289 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29290 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29292 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29293 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29295 this.bodyEl.on('click', this.onClick, this);
29296 this.downloadBtn.on('click', this.onDownload, this);
29297 this.trashBtn.on('click', this.onTrash, this);
29299 this.downloadBtn.hide();
29300 this.trashBtn.hide();
29302 if(this.showDownload){
29303 this.downloadBtn.show();
29306 if(this.showTrash){
29307 this.trashBtn.show();
29310 if(!this.showDownload && !this.showTrash) {
29311 this.footerEl.hide();
29316 initial : function()
29318 this.fireEvent('initial', this);
29322 onClick : function(e)
29324 e.preventDefault();
29326 this.fireEvent('click', this);
29329 onDownload : function(e)
29331 e.preventDefault();
29333 this.fireEvent('download', this);
29336 onTrash : function(e)
29338 e.preventDefault();
29340 this.fireEvent('trash', this);
29352 * @class Roo.bootstrap.NavProgressBar
29353 * @extends Roo.bootstrap.Component
29354 * Bootstrap NavProgressBar class
29357 * Create a new nav progress bar
29358 * @param {Object} config The config object
29361 Roo.bootstrap.NavProgressBar = function(config){
29362 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29364 this.bullets = this.bullets || [];
29366 // Roo.bootstrap.NavProgressBar.register(this);
29370 * Fires when the active item changes
29371 * @param {Roo.bootstrap.NavProgressBar} this
29372 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29373 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29380 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29385 getAutoCreate : function()
29387 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29391 cls : 'roo-navigation-bar-group',
29395 cls : 'roo-navigation-top-bar'
29399 cls : 'roo-navigation-bullets-bar',
29403 cls : 'roo-navigation-bar'
29410 cls : 'roo-navigation-bottom-bar'
29420 initEvents: function()
29425 onRender : function(ct, position)
29427 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29429 if(this.bullets.length){
29430 Roo.each(this.bullets, function(b){
29439 addItem : function(cfg)
29441 var item = new Roo.bootstrap.NavProgressItem(cfg);
29443 item.parentId = this.id;
29444 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29447 var top = new Roo.bootstrap.Element({
29449 cls : 'roo-navigation-bar-text'
29452 var bottom = new Roo.bootstrap.Element({
29454 cls : 'roo-navigation-bar-text'
29457 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29458 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29460 var topText = new Roo.bootstrap.Element({
29462 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29465 var bottomText = new Roo.bootstrap.Element({
29467 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29470 topText.onRender(top.el, null);
29471 bottomText.onRender(bottom.el, null);
29474 item.bottomEl = bottom;
29477 this.barItems.push(item);
29482 getActive : function()
29484 var active = false;
29486 Roo.each(this.barItems, function(v){
29488 if (!v.isActive()) {
29500 setActiveItem : function(item)
29504 Roo.each(this.barItems, function(v){
29505 if (v.rid == item.rid) {
29509 if (v.isActive()) {
29510 v.setActive(false);
29515 item.setActive(true);
29517 this.fireEvent('changed', this, item, prev);
29520 getBarItem: function(rid)
29524 Roo.each(this.barItems, function(e) {
29525 if (e.rid != rid) {
29536 indexOfItem : function(item)
29540 Roo.each(this.barItems, function(v, i){
29542 if (v.rid != item.rid) {
29553 setActiveNext : function()
29555 var i = this.indexOfItem(this.getActive());
29557 if (i > this.barItems.length) {
29561 this.setActiveItem(this.barItems[i+1]);
29564 setActivePrev : function()
29566 var i = this.indexOfItem(this.getActive());
29572 this.setActiveItem(this.barItems[i-1]);
29575 format : function()
29577 if(!this.barItems.length){
29581 var width = 100 / this.barItems.length;
29583 Roo.each(this.barItems, function(i){
29584 i.el.setStyle('width', width + '%');
29585 i.topEl.el.setStyle('width', width + '%');
29586 i.bottomEl.el.setStyle('width', width + '%');
29595 * Nav Progress Item
29600 * @class Roo.bootstrap.NavProgressItem
29601 * @extends Roo.bootstrap.Component
29602 * Bootstrap NavProgressItem class
29603 * @cfg {String} rid the reference id
29604 * @cfg {Boolean} active (true|false) Is item active default false
29605 * @cfg {Boolean} disabled (true|false) Is item active default false
29606 * @cfg {String} html
29607 * @cfg {String} position (top|bottom) text position default bottom
29608 * @cfg {String} icon show icon instead of number
29611 * Create a new NavProgressItem
29612 * @param {Object} config The config object
29614 Roo.bootstrap.NavProgressItem = function(config){
29615 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29620 * The raw click event for the entire grid.
29621 * @param {Roo.bootstrap.NavProgressItem} this
29622 * @param {Roo.EventObject} e
29629 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29635 position : 'bottom',
29638 getAutoCreate : function()
29640 var iconCls = 'roo-navigation-bar-item-icon';
29642 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29646 cls: 'roo-navigation-bar-item',
29656 cfg.cls += ' active';
29659 cfg.cls += ' disabled';
29665 disable : function()
29667 this.setDisabled(true);
29670 enable : function()
29672 this.setDisabled(false);
29675 initEvents: function()
29677 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29679 this.iconEl.on('click', this.onClick, this);
29682 onClick : function(e)
29684 e.preventDefault();
29690 if(this.fireEvent('click', this, e) === false){
29694 this.parent().setActiveItem(this);
29697 isActive: function ()
29699 return this.active;
29702 setActive : function(state)
29704 if(this.active == state){
29708 this.active = state;
29711 this.el.addClass('active');
29715 this.el.removeClass('active');
29720 setDisabled : function(state)
29722 if(this.disabled == state){
29726 this.disabled = state;
29729 this.el.addClass('disabled');
29733 this.el.removeClass('disabled');
29736 tooltipEl : function()
29738 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29751 * @class Roo.bootstrap.FieldLabel
29752 * @extends Roo.bootstrap.Component
29753 * Bootstrap FieldLabel class
29754 * @cfg {String} html contents of the element
29755 * @cfg {String} tag tag of the element default label
29756 * @cfg {String} cls class of the element
29757 * @cfg {String} target label target
29758 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29759 * @cfg {String} invalidClass default "text-warning"
29760 * @cfg {String} validClass default "text-success"
29761 * @cfg {String} iconTooltip default "This field is required"
29762 * @cfg {String} indicatorpos (left|right) default left
29765 * Create a new FieldLabel
29766 * @param {Object} config The config object
29769 Roo.bootstrap.FieldLabel = function(config){
29770 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29775 * Fires after the field has been marked as invalid.
29776 * @param {Roo.form.FieldLabel} this
29777 * @param {String} msg The validation message
29782 * Fires after the field has been validated with no errors.
29783 * @param {Roo.form.FieldLabel} this
29789 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29796 invalidClass : 'has-warning',
29797 validClass : 'has-success',
29798 iconTooltip : 'This field is required',
29799 indicatorpos : 'left',
29801 getAutoCreate : function(){
29805 cls : 'roo-bootstrap-field-label ' + this.cls,
29810 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29811 tooltip : this.iconTooltip
29820 if(this.indicatorpos == 'right'){
29823 cls : 'roo-bootstrap-field-label ' + this.cls,
29832 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29833 tooltip : this.iconTooltip
29842 initEvents: function()
29844 Roo.bootstrap.Element.superclass.initEvents.call(this);
29846 this.indicator = this.indicatorEl();
29848 if(this.indicator){
29849 this.indicator.removeClass('visible');
29850 this.indicator.addClass('invisible');
29853 Roo.bootstrap.FieldLabel.register(this);
29856 indicatorEl : function()
29858 var indicator = this.el.select('i.roo-required-indicator',true).first();
29869 * Mark this field as valid
29871 markValid : function()
29873 if(this.indicator){
29874 this.indicator.removeClass('visible');
29875 this.indicator.addClass('invisible');
29878 this.el.removeClass(this.invalidClass);
29880 this.el.addClass(this.validClass);
29882 this.fireEvent('valid', this);
29886 * Mark this field as invalid
29887 * @param {String} msg The validation message
29889 markInvalid : function(msg)
29891 if(this.indicator){
29892 this.indicator.removeClass('invisible');
29893 this.indicator.addClass('visible');
29896 this.el.removeClass(this.validClass);
29898 this.el.addClass(this.invalidClass);
29900 this.fireEvent('invalid', this, msg);
29906 Roo.apply(Roo.bootstrap.FieldLabel, {
29911 * register a FieldLabel Group
29912 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29914 register : function(label)
29916 if(this.groups.hasOwnProperty(label.target)){
29920 this.groups[label.target] = label;
29924 * fetch a FieldLabel Group based on the target
29925 * @param {string} target
29926 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29928 get: function(target) {
29929 if (typeof(this.groups[target]) == 'undefined') {
29933 return this.groups[target] ;
29942 * page DateSplitField.
29948 * @class Roo.bootstrap.DateSplitField
29949 * @extends Roo.bootstrap.Component
29950 * Bootstrap DateSplitField class
29951 * @cfg {string} fieldLabel - the label associated
29952 * @cfg {Number} labelWidth set the width of label (0-12)
29953 * @cfg {String} labelAlign (top|left)
29954 * @cfg {Boolean} dayAllowBlank (true|false) default false
29955 * @cfg {Boolean} monthAllowBlank (true|false) default false
29956 * @cfg {Boolean} yearAllowBlank (true|false) default false
29957 * @cfg {string} dayPlaceholder
29958 * @cfg {string} monthPlaceholder
29959 * @cfg {string} yearPlaceholder
29960 * @cfg {string} dayFormat default 'd'
29961 * @cfg {string} monthFormat default 'm'
29962 * @cfg {string} yearFormat default 'Y'
29963 * @cfg {Number} labellg set the width of label (1-12)
29964 * @cfg {Number} labelmd set the width of label (1-12)
29965 * @cfg {Number} labelsm set the width of label (1-12)
29966 * @cfg {Number} labelxs set the width of label (1-12)
29970 * Create a new DateSplitField
29971 * @param {Object} config The config object
29974 Roo.bootstrap.DateSplitField = function(config){
29975 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29981 * getting the data of years
29982 * @param {Roo.bootstrap.DateSplitField} this
29983 * @param {Object} years
29988 * getting the data of days
29989 * @param {Roo.bootstrap.DateSplitField} this
29990 * @param {Object} days
29995 * Fires after the field has been marked as invalid.
29996 * @param {Roo.form.Field} this
29997 * @param {String} msg The validation message
30002 * Fires after the field has been validated with no errors.
30003 * @param {Roo.form.Field} this
30009 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30012 labelAlign : 'top',
30014 dayAllowBlank : false,
30015 monthAllowBlank : false,
30016 yearAllowBlank : false,
30017 dayPlaceholder : '',
30018 monthPlaceholder : '',
30019 yearPlaceholder : '',
30023 isFormField : true,
30029 getAutoCreate : function()
30033 cls : 'row roo-date-split-field-group',
30038 cls : 'form-hidden-field roo-date-split-field-group-value',
30044 var labelCls = 'col-md-12';
30045 var contentCls = 'col-md-4';
30047 if(this.fieldLabel){
30051 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30055 html : this.fieldLabel
30060 if(this.labelAlign == 'left'){
30062 if(this.labelWidth > 12){
30063 label.style = "width: " + this.labelWidth + 'px';
30066 if(this.labelWidth < 13 && this.labelmd == 0){
30067 this.labelmd = this.labelWidth;
30070 if(this.labellg > 0){
30071 labelCls = ' col-lg-' + this.labellg;
30072 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30075 if(this.labelmd > 0){
30076 labelCls = ' col-md-' + this.labelmd;
30077 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30080 if(this.labelsm > 0){
30081 labelCls = ' col-sm-' + this.labelsm;
30082 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30085 if(this.labelxs > 0){
30086 labelCls = ' col-xs-' + this.labelxs;
30087 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30091 label.cls += ' ' + labelCls;
30093 cfg.cn.push(label);
30096 Roo.each(['day', 'month', 'year'], function(t){
30099 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30106 inputEl: function ()
30108 return this.el.select('.roo-date-split-field-group-value', true).first();
30111 onRender : function(ct, position)
30115 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30117 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30119 this.dayField = new Roo.bootstrap.ComboBox({
30120 allowBlank : this.dayAllowBlank,
30121 alwaysQuery : true,
30122 displayField : 'value',
30125 forceSelection : true,
30127 placeholder : this.dayPlaceholder,
30128 selectOnFocus : true,
30129 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30130 triggerAction : 'all',
30132 valueField : 'value',
30133 store : new Roo.data.SimpleStore({
30134 data : (function() {
30136 _this.fireEvent('days', _this, days);
30139 fields : [ 'value' ]
30142 select : function (_self, record, index)
30144 _this.setValue(_this.getValue());
30149 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30151 this.monthField = new Roo.bootstrap.MonthField({
30152 after : '<i class=\"fa fa-calendar\"></i>',
30153 allowBlank : this.monthAllowBlank,
30154 placeholder : this.monthPlaceholder,
30157 render : function (_self)
30159 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30160 e.preventDefault();
30164 select : function (_self, oldvalue, newvalue)
30166 _this.setValue(_this.getValue());
30171 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30173 this.yearField = new Roo.bootstrap.ComboBox({
30174 allowBlank : this.yearAllowBlank,
30175 alwaysQuery : true,
30176 displayField : 'value',
30179 forceSelection : true,
30181 placeholder : this.yearPlaceholder,
30182 selectOnFocus : true,
30183 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30184 triggerAction : 'all',
30186 valueField : 'value',
30187 store : new Roo.data.SimpleStore({
30188 data : (function() {
30190 _this.fireEvent('years', _this, years);
30193 fields : [ 'value' ]
30196 select : function (_self, record, index)
30198 _this.setValue(_this.getValue());
30203 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30206 setValue : function(v, format)
30208 this.inputEl.dom.value = v;
30210 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30212 var d = Date.parseDate(v, f);
30219 this.setDay(d.format(this.dayFormat));
30220 this.setMonth(d.format(this.monthFormat));
30221 this.setYear(d.format(this.yearFormat));
30228 setDay : function(v)
30230 this.dayField.setValue(v);
30231 this.inputEl.dom.value = this.getValue();
30236 setMonth : function(v)
30238 this.monthField.setValue(v, true);
30239 this.inputEl.dom.value = this.getValue();
30244 setYear : function(v)
30246 this.yearField.setValue(v);
30247 this.inputEl.dom.value = this.getValue();
30252 getDay : function()
30254 return this.dayField.getValue();
30257 getMonth : function()
30259 return this.monthField.getValue();
30262 getYear : function()
30264 return this.yearField.getValue();
30267 getValue : function()
30269 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30271 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30281 this.inputEl.dom.value = '';
30286 validate : function()
30288 var d = this.dayField.validate();
30289 var m = this.monthField.validate();
30290 var y = this.yearField.validate();
30295 (!this.dayAllowBlank && !d) ||
30296 (!this.monthAllowBlank && !m) ||
30297 (!this.yearAllowBlank && !y)
30302 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30311 this.markInvalid();
30316 markValid : function()
30319 var label = this.el.select('label', true).first();
30320 var icon = this.el.select('i.fa-star', true).first();
30326 this.fireEvent('valid', this);
30330 * Mark this field as invalid
30331 * @param {String} msg The validation message
30333 markInvalid : function(msg)
30336 var label = this.el.select('label', true).first();
30337 var icon = this.el.select('i.fa-star', true).first();
30339 if(label && !icon){
30340 this.el.select('.roo-date-split-field-label', true).createChild({
30342 cls : 'text-danger fa fa-lg fa-star',
30343 tooltip : 'This field is required',
30344 style : 'margin-right:5px;'
30348 this.fireEvent('invalid', this, msg);
30351 clearInvalid : function()
30353 var label = this.el.select('label', true).first();
30354 var icon = this.el.select('i.fa-star', true).first();
30360 this.fireEvent('valid', this);
30363 getName: function()
30373 * http://masonry.desandro.com
30375 * The idea is to render all the bricks based on vertical width...
30377 * The original code extends 'outlayer' - we might need to use that....
30383 * @class Roo.bootstrap.LayoutMasonry
30384 * @extends Roo.bootstrap.Component
30385 * Bootstrap Layout Masonry class
30388 * Create a new Element
30389 * @param {Object} config The config object
30392 Roo.bootstrap.LayoutMasonry = function(config){
30394 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30398 Roo.bootstrap.LayoutMasonry.register(this);
30404 * Fire after layout the items
30405 * @param {Roo.bootstrap.LayoutMasonry} this
30406 * @param {Roo.EventObject} e
30413 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30416 * @cfg {Boolean} isLayoutInstant = no animation?
30418 isLayoutInstant : false, // needed?
30421 * @cfg {Number} boxWidth width of the columns
30426 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30431 * @cfg {Number} padWidth padding below box..
30436 * @cfg {Number} gutter gutter width..
30441 * @cfg {Number} maxCols maximum number of columns
30447 * @cfg {Boolean} isAutoInitial defalut true
30449 isAutoInitial : true,
30454 * @cfg {Boolean} isHorizontal defalut false
30456 isHorizontal : false,
30458 currentSize : null,
30464 bricks: null, //CompositeElement
30468 _isLayoutInited : false,
30470 // isAlternative : false, // only use for vertical layout...
30473 * @cfg {Number} alternativePadWidth padding below box..
30475 alternativePadWidth : 50,
30477 selectedBrick : [],
30479 getAutoCreate : function(){
30481 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30485 cls: 'blog-masonary-wrapper ' + this.cls,
30487 cls : 'mas-boxes masonary'
30494 getChildContainer: function( )
30496 if (this.boxesEl) {
30497 return this.boxesEl;
30500 this.boxesEl = this.el.select('.mas-boxes').first();
30502 return this.boxesEl;
30506 initEvents : function()
30510 if(this.isAutoInitial){
30511 Roo.log('hook children rendered');
30512 this.on('childrenrendered', function() {
30513 Roo.log('children rendered');
30519 initial : function()
30521 this.selectedBrick = [];
30523 this.currentSize = this.el.getBox(true);
30525 Roo.EventManager.onWindowResize(this.resize, this);
30527 if(!this.isAutoInitial){
30535 //this.layout.defer(500,this);
30539 resize : function()
30541 var cs = this.el.getBox(true);
30544 this.currentSize.width == cs.width &&
30545 this.currentSize.x == cs.x &&
30546 this.currentSize.height == cs.height &&
30547 this.currentSize.y == cs.y
30549 Roo.log("no change in with or X or Y");
30553 this.currentSize = cs;
30559 layout : function()
30561 this._resetLayout();
30563 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30565 this.layoutItems( isInstant );
30567 this._isLayoutInited = true;
30569 this.fireEvent('layout', this);
30573 _resetLayout : function()
30575 if(this.isHorizontal){
30576 this.horizontalMeasureColumns();
30580 this.verticalMeasureColumns();
30584 verticalMeasureColumns : function()
30586 this.getContainerWidth();
30588 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30589 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30593 var boxWidth = this.boxWidth + this.padWidth;
30595 if(this.containerWidth < this.boxWidth){
30596 boxWidth = this.containerWidth
30599 var containerWidth = this.containerWidth;
30601 var cols = Math.floor(containerWidth / boxWidth);
30603 this.cols = Math.max( cols, 1 );
30605 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30607 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30609 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30611 this.colWidth = boxWidth + avail - this.padWidth;
30613 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30614 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30617 horizontalMeasureColumns : function()
30619 this.getContainerWidth();
30621 var boxWidth = this.boxWidth;
30623 if(this.containerWidth < boxWidth){
30624 boxWidth = this.containerWidth;
30627 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30629 this.el.setHeight(boxWidth);
30633 getContainerWidth : function()
30635 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30638 layoutItems : function( isInstant )
30640 Roo.log(this.bricks);
30642 var items = Roo.apply([], this.bricks);
30644 if(this.isHorizontal){
30645 this._horizontalLayoutItems( items , isInstant );
30649 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30650 // this._verticalAlternativeLayoutItems( items , isInstant );
30654 this._verticalLayoutItems( items , isInstant );
30658 _verticalLayoutItems : function ( items , isInstant)
30660 if ( !items || !items.length ) {
30665 ['xs', 'xs', 'xs', 'tall'],
30666 ['xs', 'xs', 'tall'],
30667 ['xs', 'xs', 'sm'],
30668 ['xs', 'xs', 'xs'],
30674 ['sm', 'xs', 'xs'],
30678 ['tall', 'xs', 'xs', 'xs'],
30679 ['tall', 'xs', 'xs'],
30691 Roo.each(items, function(item, k){
30693 switch (item.size) {
30694 // these layouts take up a full box,
30705 boxes.push([item]);
30728 var filterPattern = function(box, length)
30736 var pattern = box.slice(0, length);
30740 Roo.each(pattern, function(i){
30741 format.push(i.size);
30744 Roo.each(standard, function(s){
30746 if(String(s) != String(format)){
30755 if(!match && length == 1){
30760 filterPattern(box, length - 1);
30764 queue.push(pattern);
30766 box = box.slice(length, box.length);
30768 filterPattern(box, 4);
30774 Roo.each(boxes, function(box, k){
30780 if(box.length == 1){
30785 filterPattern(box, 4);
30789 this._processVerticalLayoutQueue( queue, isInstant );
30793 // _verticalAlternativeLayoutItems : function( items , isInstant )
30795 // if ( !items || !items.length ) {
30799 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30803 _horizontalLayoutItems : function ( items , isInstant)
30805 if ( !items || !items.length || items.length < 3) {
30811 var eItems = items.slice(0, 3);
30813 items = items.slice(3, items.length);
30816 ['xs', 'xs', 'xs', 'wide'],
30817 ['xs', 'xs', 'wide'],
30818 ['xs', 'xs', 'sm'],
30819 ['xs', 'xs', 'xs'],
30825 ['sm', 'xs', 'xs'],
30829 ['wide', 'xs', 'xs', 'xs'],
30830 ['wide', 'xs', 'xs'],
30843 Roo.each(items, function(item, k){
30845 switch (item.size) {
30856 boxes.push([item]);
30880 var filterPattern = function(box, length)
30888 var pattern = box.slice(0, length);
30892 Roo.each(pattern, function(i){
30893 format.push(i.size);
30896 Roo.each(standard, function(s){
30898 if(String(s) != String(format)){
30907 if(!match && length == 1){
30912 filterPattern(box, length - 1);
30916 queue.push(pattern);
30918 box = box.slice(length, box.length);
30920 filterPattern(box, 4);
30926 Roo.each(boxes, function(box, k){
30932 if(box.length == 1){
30937 filterPattern(box, 4);
30944 var pos = this.el.getBox(true);
30948 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30950 var hit_end = false;
30952 Roo.each(queue, function(box){
30956 Roo.each(box, function(b){
30958 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30968 Roo.each(box, function(b){
30970 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30973 mx = Math.max(mx, b.x);
30977 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30981 Roo.each(box, function(b){
30983 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30997 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31000 /** Sets position of item in DOM
31001 * @param {Element} item
31002 * @param {Number} x - horizontal position
31003 * @param {Number} y - vertical position
31004 * @param {Boolean} isInstant - disables transitions
31006 _processVerticalLayoutQueue : function( queue, isInstant )
31008 var pos = this.el.getBox(true);
31013 for (var i = 0; i < this.cols; i++){
31017 Roo.each(queue, function(box, k){
31019 var col = k % this.cols;
31021 Roo.each(box, function(b,kk){
31023 b.el.position('absolute');
31025 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31026 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31028 if(b.size == 'md-left' || b.size == 'md-right'){
31029 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31030 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31033 b.el.setWidth(width);
31034 b.el.setHeight(height);
31036 b.el.select('iframe',true).setSize(width,height);
31040 for (var i = 0; i < this.cols; i++){
31042 if(maxY[i] < maxY[col]){
31047 col = Math.min(col, i);
31051 x = pos.x + col * (this.colWidth + this.padWidth);
31055 var positions = [];
31057 switch (box.length){
31059 positions = this.getVerticalOneBoxColPositions(x, y, box);
31062 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31065 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31068 positions = this.getVerticalFourBoxColPositions(x, y, box);
31074 Roo.each(box, function(b,kk){
31076 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31078 var sz = b.el.getSize();
31080 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31088 for (var i = 0; i < this.cols; i++){
31089 mY = Math.max(mY, maxY[i]);
31092 this.el.setHeight(mY - pos.y);
31096 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31098 // var pos = this.el.getBox(true);
31101 // var maxX = pos.right;
31103 // var maxHeight = 0;
31105 // Roo.each(items, function(item, k){
31109 // item.el.position('absolute');
31111 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31113 // item.el.setWidth(width);
31115 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31117 // item.el.setHeight(height);
31120 // item.el.setXY([x, y], isInstant ? false : true);
31122 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31125 // y = y + height + this.alternativePadWidth;
31127 // maxHeight = maxHeight + height + this.alternativePadWidth;
31131 // this.el.setHeight(maxHeight);
31135 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31137 var pos = this.el.getBox(true);
31142 var maxX = pos.right;
31144 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31146 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31148 Roo.each(queue, function(box, k){
31150 Roo.each(box, function(b, kk){
31152 b.el.position('absolute');
31154 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31155 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31157 if(b.size == 'md-left' || b.size == 'md-right'){
31158 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31159 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31162 b.el.setWidth(width);
31163 b.el.setHeight(height);
31171 var positions = [];
31173 switch (box.length){
31175 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31178 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31181 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31184 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31190 Roo.each(box, function(b,kk){
31192 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31194 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31202 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31204 Roo.each(eItems, function(b,k){
31206 b.size = (k == 0) ? 'sm' : 'xs';
31207 b.x = (k == 0) ? 2 : 1;
31208 b.y = (k == 0) ? 2 : 1;
31210 b.el.position('absolute');
31212 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31214 b.el.setWidth(width);
31216 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31218 b.el.setHeight(height);
31222 var positions = [];
31225 x : maxX - this.unitWidth * 2 - this.gutter,
31230 x : maxX - this.unitWidth,
31231 y : minY + (this.unitWidth + this.gutter) * 2
31235 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31239 Roo.each(eItems, function(b,k){
31241 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31247 getVerticalOneBoxColPositions : function(x, y, box)
31251 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31253 if(box[0].size == 'md-left'){
31257 if(box[0].size == 'md-right'){
31262 x : x + (this.unitWidth + this.gutter) * rand,
31269 getVerticalTwoBoxColPositions : function(x, y, box)
31273 if(box[0].size == 'xs'){
31277 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31281 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31295 x : x + (this.unitWidth + this.gutter) * 2,
31296 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31303 getVerticalThreeBoxColPositions : function(x, y, box)
31307 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31315 x : x + (this.unitWidth + this.gutter) * 1,
31320 x : x + (this.unitWidth + this.gutter) * 2,
31328 if(box[0].size == 'xs' && box[1].size == 'xs'){
31337 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31341 x : x + (this.unitWidth + this.gutter) * 1,
31355 x : x + (this.unitWidth + this.gutter) * 2,
31360 x : x + (this.unitWidth + this.gutter) * 2,
31361 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31368 getVerticalFourBoxColPositions : function(x, y, box)
31372 if(box[0].size == 'xs'){
31381 y : y + (this.unitHeight + this.gutter) * 1
31386 y : y + (this.unitHeight + this.gutter) * 2
31390 x : x + (this.unitWidth + this.gutter) * 1,
31404 x : x + (this.unitWidth + this.gutter) * 2,
31409 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31410 y : y + (this.unitHeight + this.gutter) * 1
31414 x : x + (this.unitWidth + this.gutter) * 2,
31415 y : y + (this.unitWidth + this.gutter) * 2
31422 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31426 if(box[0].size == 'md-left'){
31428 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31435 if(box[0].size == 'md-right'){
31437 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31438 y : minY + (this.unitWidth + this.gutter) * 1
31444 var rand = Math.floor(Math.random() * (4 - box[0].y));
31447 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31448 y : minY + (this.unitWidth + this.gutter) * rand
31455 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31459 if(box[0].size == 'xs'){
31462 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31467 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31468 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31476 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31481 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31482 y : minY + (this.unitWidth + this.gutter) * 2
31489 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31493 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31496 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31501 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31502 y : minY + (this.unitWidth + this.gutter) * 1
31506 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31507 y : minY + (this.unitWidth + this.gutter) * 2
31514 if(box[0].size == 'xs' && box[1].size == 'xs'){
31517 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31522 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31527 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31528 y : minY + (this.unitWidth + this.gutter) * 1
31536 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31541 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31542 y : minY + (this.unitWidth + this.gutter) * 2
31546 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31547 y : minY + (this.unitWidth + this.gutter) * 2
31554 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31558 if(box[0].size == 'xs'){
31561 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31566 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31571 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),
31576 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31577 y : minY + (this.unitWidth + this.gutter) * 1
31585 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31590 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31591 y : minY + (this.unitWidth + this.gutter) * 2
31595 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31596 y : minY + (this.unitWidth + this.gutter) * 2
31600 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),
31601 y : minY + (this.unitWidth + this.gutter) * 2
31609 * remove a Masonry Brick
31610 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31612 removeBrick : function(brick_id)
31618 for (var i = 0; i<this.bricks.length; i++) {
31619 if (this.bricks[i].id == brick_id) {
31620 this.bricks.splice(i,1);
31621 this.el.dom.removeChild(Roo.get(brick_id).dom);
31628 * adds a Masonry Brick
31629 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31631 addBrick : function(cfg)
31633 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31634 //this.register(cn);
31635 cn.parentId = this.id;
31636 cn.onRender(this.el, null);
31641 * register a Masonry Brick
31642 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31645 register : function(brick)
31647 this.bricks.push(brick);
31648 brick.masonryId = this.id;
31652 * clear all the Masonry Brick
31654 clearAll : function()
31657 //this.getChildContainer().dom.innerHTML = "";
31658 this.el.dom.innerHTML = '';
31661 getSelected : function()
31663 if (!this.selectedBrick) {
31667 return this.selectedBrick;
31671 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31675 * register a Masonry Layout
31676 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31679 register : function(layout)
31681 this.groups[layout.id] = layout;
31684 * fetch a Masonry Layout based on the masonry layout ID
31685 * @param {string} the masonry layout to add
31686 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31689 get: function(layout_id) {
31690 if (typeof(this.groups[layout_id]) == 'undefined') {
31693 return this.groups[layout_id] ;
31705 * http://masonry.desandro.com
31707 * The idea is to render all the bricks based on vertical width...
31709 * The original code extends 'outlayer' - we might need to use that....
31715 * @class Roo.bootstrap.LayoutMasonryAuto
31716 * @extends Roo.bootstrap.Component
31717 * Bootstrap Layout Masonry class
31720 * Create a new Element
31721 * @param {Object} config The config object
31724 Roo.bootstrap.LayoutMasonryAuto = function(config){
31725 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31728 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31731 * @cfg {Boolean} isFitWidth - resize the width..
31733 isFitWidth : false, // options..
31735 * @cfg {Boolean} isOriginLeft = left align?
31737 isOriginLeft : true,
31739 * @cfg {Boolean} isOriginTop = top align?
31741 isOriginTop : false,
31743 * @cfg {Boolean} isLayoutInstant = no animation?
31745 isLayoutInstant : false, // needed?
31747 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31749 isResizingContainer : true,
31751 * @cfg {Number} columnWidth width of the columns
31757 * @cfg {Number} maxCols maximum number of columns
31762 * @cfg {Number} padHeight padding below box..
31768 * @cfg {Boolean} isAutoInitial defalut true
31771 isAutoInitial : true,
31777 initialColumnWidth : 0,
31778 currentSize : null,
31780 colYs : null, // array.
31787 bricks: null, //CompositeElement
31788 cols : 0, // array?
31789 // element : null, // wrapped now this.el
31790 _isLayoutInited : null,
31793 getAutoCreate : function(){
31797 cls: 'blog-masonary-wrapper ' + this.cls,
31799 cls : 'mas-boxes masonary'
31806 getChildContainer: function( )
31808 if (this.boxesEl) {
31809 return this.boxesEl;
31812 this.boxesEl = this.el.select('.mas-boxes').first();
31814 return this.boxesEl;
31818 initEvents : function()
31822 if(this.isAutoInitial){
31823 Roo.log('hook children rendered');
31824 this.on('childrenrendered', function() {
31825 Roo.log('children rendered');
31832 initial : function()
31834 this.reloadItems();
31836 this.currentSize = this.el.getBox(true);
31838 /// was window resize... - let's see if this works..
31839 Roo.EventManager.onWindowResize(this.resize, this);
31841 if(!this.isAutoInitial){
31846 this.layout.defer(500,this);
31849 reloadItems: function()
31851 this.bricks = this.el.select('.masonry-brick', true);
31853 this.bricks.each(function(b) {
31854 //Roo.log(b.getSize());
31855 if (!b.attr('originalwidth')) {
31856 b.attr('originalwidth', b.getSize().width);
31861 Roo.log(this.bricks.elements.length);
31864 resize : function()
31867 var cs = this.el.getBox(true);
31869 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31870 Roo.log("no change in with or X");
31873 this.currentSize = cs;
31877 layout : function()
31880 this._resetLayout();
31881 //this._manageStamps();
31883 // don't animate first layout
31884 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31885 this.layoutItems( isInstant );
31887 // flag for initalized
31888 this._isLayoutInited = true;
31891 layoutItems : function( isInstant )
31893 //var items = this._getItemsForLayout( this.items );
31894 // original code supports filtering layout items.. we just ignore it..
31896 this._layoutItems( this.bricks , isInstant );
31898 this._postLayout();
31900 _layoutItems : function ( items , isInstant)
31902 //this.fireEvent( 'layout', this, items );
31905 if ( !items || !items.elements.length ) {
31906 // no items, emit event with empty array
31911 items.each(function(item) {
31912 Roo.log("layout item");
31914 // get x/y object from method
31915 var position = this._getItemLayoutPosition( item );
31917 position.item = item;
31918 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31919 queue.push( position );
31922 this._processLayoutQueue( queue );
31924 /** Sets position of item in DOM
31925 * @param {Element} item
31926 * @param {Number} x - horizontal position
31927 * @param {Number} y - vertical position
31928 * @param {Boolean} isInstant - disables transitions
31930 _processLayoutQueue : function( queue )
31932 for ( var i=0, len = queue.length; i < len; i++ ) {
31933 var obj = queue[i];
31934 obj.item.position('absolute');
31935 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31941 * Any logic you want to do after each layout,
31942 * i.e. size the container
31944 _postLayout : function()
31946 this.resizeContainer();
31949 resizeContainer : function()
31951 if ( !this.isResizingContainer ) {
31954 var size = this._getContainerSize();
31956 this.el.setSize(size.width,size.height);
31957 this.boxesEl.setSize(size.width,size.height);
31963 _resetLayout : function()
31965 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31966 this.colWidth = this.el.getWidth();
31967 //this.gutter = this.el.getWidth();
31969 this.measureColumns();
31975 this.colYs.push( 0 );
31981 measureColumns : function()
31983 this.getContainerWidth();
31984 // if columnWidth is 0, default to outerWidth of first item
31985 if ( !this.columnWidth ) {
31986 var firstItem = this.bricks.first();
31987 Roo.log(firstItem);
31988 this.columnWidth = this.containerWidth;
31989 if (firstItem && firstItem.attr('originalwidth') ) {
31990 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31992 // columnWidth fall back to item of first element
31993 Roo.log("set column width?");
31994 this.initialColumnWidth = this.columnWidth ;
31996 // if first elem has no width, default to size of container
32001 if (this.initialColumnWidth) {
32002 this.columnWidth = this.initialColumnWidth;
32007 // column width is fixed at the top - however if container width get's smaller we should
32010 // this bit calcs how man columns..
32012 var columnWidth = this.columnWidth += this.gutter;
32014 // calculate columns
32015 var containerWidth = this.containerWidth + this.gutter;
32017 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32018 // fix rounding errors, typically with gutters
32019 var excess = columnWidth - containerWidth % columnWidth;
32022 // if overshoot is less than a pixel, round up, otherwise floor it
32023 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32024 cols = Math[ mathMethod ]( cols );
32025 this.cols = Math.max( cols, 1 );
32026 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32028 // padding positioning..
32029 var totalColWidth = this.cols * this.columnWidth;
32030 var padavail = this.containerWidth - totalColWidth;
32031 // so for 2 columns - we need 3 'pads'
32033 var padNeeded = (1+this.cols) * this.padWidth;
32035 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32037 this.columnWidth += padExtra
32038 //this.padWidth = Math.floor(padavail / ( this.cols));
32040 // adjust colum width so that padding is fixed??
32042 // we have 3 columns ... total = width * 3
32043 // we have X left over... that should be used by
32045 //if (this.expandC) {
32053 getContainerWidth : function()
32055 /* // container is parent if fit width
32056 var container = this.isFitWidth ? this.element.parentNode : this.element;
32057 // check that this.size and size are there
32058 // IE8 triggers resize on body size change, so they might not be
32060 var size = getSize( container ); //FIXME
32061 this.containerWidth = size && size.innerWidth; //FIXME
32064 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32068 _getItemLayoutPosition : function( item ) // what is item?
32070 // we resize the item to our columnWidth..
32072 item.setWidth(this.columnWidth);
32073 item.autoBoxAdjust = false;
32075 var sz = item.getSize();
32077 // how many columns does this brick span
32078 var remainder = this.containerWidth % this.columnWidth;
32080 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32081 // round if off by 1 pixel, otherwise use ceil
32082 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32083 colSpan = Math.min( colSpan, this.cols );
32085 // normally this should be '1' as we dont' currently allow multi width columns..
32087 var colGroup = this._getColGroup( colSpan );
32088 // get the minimum Y value from the columns
32089 var minimumY = Math.min.apply( Math, colGroup );
32090 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32092 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32094 // position the brick
32096 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32097 y: this.currentSize.y + minimumY + this.padHeight
32101 // apply setHeight to necessary columns
32102 var setHeight = minimumY + sz.height + this.padHeight;
32103 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32105 var setSpan = this.cols + 1 - colGroup.length;
32106 for ( var i = 0; i < setSpan; i++ ) {
32107 this.colYs[ shortColIndex + i ] = setHeight ;
32114 * @param {Number} colSpan - number of columns the element spans
32115 * @returns {Array} colGroup
32117 _getColGroup : function( colSpan )
32119 if ( colSpan < 2 ) {
32120 // if brick spans only one column, use all the column Ys
32125 // how many different places could this brick fit horizontally
32126 var groupCount = this.cols + 1 - colSpan;
32127 // for each group potential horizontal position
32128 for ( var i = 0; i < groupCount; i++ ) {
32129 // make an array of colY values for that one group
32130 var groupColYs = this.colYs.slice( i, i + colSpan );
32131 // and get the max value of the array
32132 colGroup[i] = Math.max.apply( Math, groupColYs );
32137 _manageStamp : function( stamp )
32139 var stampSize = stamp.getSize();
32140 var offset = stamp.getBox();
32141 // get the columns that this stamp affects
32142 var firstX = this.isOriginLeft ? offset.x : offset.right;
32143 var lastX = firstX + stampSize.width;
32144 var firstCol = Math.floor( firstX / this.columnWidth );
32145 firstCol = Math.max( 0, firstCol );
32147 var lastCol = Math.floor( lastX / this.columnWidth );
32148 // lastCol should not go over if multiple of columnWidth #425
32149 lastCol -= lastX % this.columnWidth ? 0 : 1;
32150 lastCol = Math.min( this.cols - 1, lastCol );
32152 // set colYs to bottom of the stamp
32153 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32156 for ( var i = firstCol; i <= lastCol; i++ ) {
32157 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32162 _getContainerSize : function()
32164 this.maxY = Math.max.apply( Math, this.colYs );
32169 if ( this.isFitWidth ) {
32170 size.width = this._getContainerFitWidth();
32176 _getContainerFitWidth : function()
32178 var unusedCols = 0;
32179 // count unused columns
32182 if ( this.colYs[i] !== 0 ) {
32187 // fit container to columns that have been used
32188 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32191 needsResizeLayout : function()
32193 var previousWidth = this.containerWidth;
32194 this.getContainerWidth();
32195 return previousWidth !== this.containerWidth;
32210 * @class Roo.bootstrap.MasonryBrick
32211 * @extends Roo.bootstrap.Component
32212 * Bootstrap MasonryBrick class
32215 * Create a new MasonryBrick
32216 * @param {Object} config The config object
32219 Roo.bootstrap.MasonryBrick = function(config){
32221 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32223 Roo.bootstrap.MasonryBrick.register(this);
32229 * When a MasonryBrick is clcik
32230 * @param {Roo.bootstrap.MasonryBrick} this
32231 * @param {Roo.EventObject} e
32237 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32240 * @cfg {String} title
32244 * @cfg {String} html
32248 * @cfg {String} bgimage
32252 * @cfg {String} videourl
32256 * @cfg {String} cls
32260 * @cfg {String} href
32264 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32269 * @cfg {String} placetitle (center|bottom)
32274 * @cfg {Boolean} isFitContainer defalut true
32276 isFitContainer : true,
32279 * @cfg {Boolean} preventDefault defalut false
32281 preventDefault : false,
32284 * @cfg {Boolean} inverse defalut false
32286 maskInverse : false,
32288 getAutoCreate : function()
32290 if(!this.isFitContainer){
32291 return this.getSplitAutoCreate();
32294 var cls = 'masonry-brick masonry-brick-full';
32296 if(this.href.length){
32297 cls += ' masonry-brick-link';
32300 if(this.bgimage.length){
32301 cls += ' masonry-brick-image';
32304 if(this.maskInverse){
32305 cls += ' mask-inverse';
32308 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32309 cls += ' enable-mask';
32313 cls += ' masonry-' + this.size + '-brick';
32316 if(this.placetitle.length){
32318 switch (this.placetitle) {
32320 cls += ' masonry-center-title';
32323 cls += ' masonry-bottom-title';
32330 if(!this.html.length && !this.bgimage.length){
32331 cls += ' masonry-center-title';
32334 if(!this.html.length && this.bgimage.length){
32335 cls += ' masonry-bottom-title';
32340 cls += ' ' + this.cls;
32344 tag: (this.href.length) ? 'a' : 'div',
32349 cls: 'masonry-brick-mask'
32353 cls: 'masonry-brick-paragraph',
32359 if(this.href.length){
32360 cfg.href = this.href;
32363 var cn = cfg.cn[1].cn;
32365 if(this.title.length){
32368 cls: 'masonry-brick-title',
32373 if(this.html.length){
32376 cls: 'masonry-brick-text',
32381 if (!this.title.length && !this.html.length) {
32382 cfg.cn[1].cls += ' hide';
32385 if(this.bgimage.length){
32388 cls: 'masonry-brick-image-view',
32393 if(this.videourl.length){
32394 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32395 // youtube support only?
32398 cls: 'masonry-brick-image-view',
32401 allowfullscreen : true
32409 getSplitAutoCreate : function()
32411 var cls = 'masonry-brick masonry-brick-split';
32413 if(this.href.length){
32414 cls += ' masonry-brick-link';
32417 if(this.bgimage.length){
32418 cls += ' masonry-brick-image';
32422 cls += ' masonry-' + this.size + '-brick';
32425 switch (this.placetitle) {
32427 cls += ' masonry-center-title';
32430 cls += ' masonry-bottom-title';
32433 if(!this.bgimage.length){
32434 cls += ' masonry-center-title';
32437 if(this.bgimage.length){
32438 cls += ' masonry-bottom-title';
32444 cls += ' ' + this.cls;
32448 tag: (this.href.length) ? 'a' : 'div',
32453 cls: 'masonry-brick-split-head',
32457 cls: 'masonry-brick-paragraph',
32464 cls: 'masonry-brick-split-body',
32470 if(this.href.length){
32471 cfg.href = this.href;
32474 if(this.title.length){
32475 cfg.cn[0].cn[0].cn.push({
32477 cls: 'masonry-brick-title',
32482 if(this.html.length){
32483 cfg.cn[1].cn.push({
32485 cls: 'masonry-brick-text',
32490 if(this.bgimage.length){
32491 cfg.cn[0].cn.push({
32493 cls: 'masonry-brick-image-view',
32498 if(this.videourl.length){
32499 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32500 // youtube support only?
32501 cfg.cn[0].cn.cn.push({
32503 cls: 'masonry-brick-image-view',
32506 allowfullscreen : true
32513 initEvents: function()
32515 switch (this.size) {
32548 this.el.on('touchstart', this.onTouchStart, this);
32549 this.el.on('touchmove', this.onTouchMove, this);
32550 this.el.on('touchend', this.onTouchEnd, this);
32551 this.el.on('contextmenu', this.onContextMenu, this);
32553 this.el.on('mouseenter' ,this.enter, this);
32554 this.el.on('mouseleave', this.leave, this);
32555 this.el.on('click', this.onClick, this);
32558 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32559 this.parent().bricks.push(this);
32564 onClick: function(e, el)
32566 var time = this.endTimer - this.startTimer;
32567 // Roo.log(e.preventDefault());
32570 e.preventDefault();
32575 if(!this.preventDefault){
32579 e.preventDefault();
32581 if (this.activcClass != '') {
32582 this.selectBrick();
32585 this.fireEvent('click', this);
32588 enter: function(e, el)
32590 e.preventDefault();
32592 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32596 if(this.bgimage.length && this.html.length){
32597 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32601 leave: function(e, el)
32603 e.preventDefault();
32605 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32609 if(this.bgimage.length && this.html.length){
32610 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32614 onTouchStart: function(e, el)
32616 // e.preventDefault();
32618 this.touchmoved = false;
32620 if(!this.isFitContainer){
32624 if(!this.bgimage.length || !this.html.length){
32628 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32630 this.timer = new Date().getTime();
32634 onTouchMove: function(e, el)
32636 this.touchmoved = true;
32639 onContextMenu : function(e,el)
32641 e.preventDefault();
32642 e.stopPropagation();
32646 onTouchEnd: function(e, el)
32648 // e.preventDefault();
32650 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32657 if(!this.bgimage.length || !this.html.length){
32659 if(this.href.length){
32660 window.location.href = this.href;
32666 if(!this.isFitContainer){
32670 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32672 window.location.href = this.href;
32675 //selection on single brick only
32676 selectBrick : function() {
32678 if (!this.parentId) {
32682 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32683 var index = m.selectedBrick.indexOf(this.id);
32686 m.selectedBrick.splice(index,1);
32687 this.el.removeClass(this.activeClass);
32691 for(var i = 0; i < m.selectedBrick.length; i++) {
32692 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32693 b.el.removeClass(b.activeClass);
32696 m.selectedBrick = [];
32698 m.selectedBrick.push(this.id);
32699 this.el.addClass(this.activeClass);
32705 Roo.apply(Roo.bootstrap.MasonryBrick, {
32708 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32710 * register a Masonry Brick
32711 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32714 register : function(brick)
32716 //this.groups[brick.id] = brick;
32717 this.groups.add(brick.id, brick);
32720 * fetch a masonry brick based on the masonry brick ID
32721 * @param {string} the masonry brick to add
32722 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32725 get: function(brick_id)
32727 // if (typeof(this.groups[brick_id]) == 'undefined') {
32730 // return this.groups[brick_id] ;
32732 if(this.groups.key(brick_id)) {
32733 return this.groups.key(brick_id);
32751 * @class Roo.bootstrap.Brick
32752 * @extends Roo.bootstrap.Component
32753 * Bootstrap Brick class
32756 * Create a new Brick
32757 * @param {Object} config The config object
32760 Roo.bootstrap.Brick = function(config){
32761 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32767 * When a Brick is click
32768 * @param {Roo.bootstrap.Brick} this
32769 * @param {Roo.EventObject} e
32775 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32778 * @cfg {String} title
32782 * @cfg {String} html
32786 * @cfg {String} bgimage
32790 * @cfg {String} cls
32794 * @cfg {String} href
32798 * @cfg {String} video
32802 * @cfg {Boolean} square
32806 getAutoCreate : function()
32808 var cls = 'roo-brick';
32810 if(this.href.length){
32811 cls += ' roo-brick-link';
32814 if(this.bgimage.length){
32815 cls += ' roo-brick-image';
32818 if(!this.html.length && !this.bgimage.length){
32819 cls += ' roo-brick-center-title';
32822 if(!this.html.length && this.bgimage.length){
32823 cls += ' roo-brick-bottom-title';
32827 cls += ' ' + this.cls;
32831 tag: (this.href.length) ? 'a' : 'div',
32836 cls: 'roo-brick-paragraph',
32842 if(this.href.length){
32843 cfg.href = this.href;
32846 var cn = cfg.cn[0].cn;
32848 if(this.title.length){
32851 cls: 'roo-brick-title',
32856 if(this.html.length){
32859 cls: 'roo-brick-text',
32866 if(this.bgimage.length){
32869 cls: 'roo-brick-image-view',
32877 initEvents: function()
32879 if(this.title.length || this.html.length){
32880 this.el.on('mouseenter' ,this.enter, this);
32881 this.el.on('mouseleave', this.leave, this);
32884 Roo.EventManager.onWindowResize(this.resize, this);
32886 if(this.bgimage.length){
32887 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32888 this.imageEl.on('load', this.onImageLoad, this);
32895 onImageLoad : function()
32900 resize : function()
32902 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32904 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32906 if(this.bgimage.length){
32907 var image = this.el.select('.roo-brick-image-view', true).first();
32909 image.setWidth(paragraph.getWidth());
32912 image.setHeight(paragraph.getWidth());
32915 this.el.setHeight(image.getHeight());
32916 paragraph.setHeight(image.getHeight());
32922 enter: function(e, el)
32924 e.preventDefault();
32926 if(this.bgimage.length){
32927 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32928 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32932 leave: function(e, el)
32934 e.preventDefault();
32936 if(this.bgimage.length){
32937 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32938 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32954 * @class Roo.bootstrap.NumberField
32955 * @extends Roo.bootstrap.Input
32956 * Bootstrap NumberField class
32962 * Create a new NumberField
32963 * @param {Object} config The config object
32966 Roo.bootstrap.NumberField = function(config){
32967 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32970 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32973 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32975 allowDecimals : true,
32977 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32979 decimalSeparator : ".",
32981 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32983 decimalPrecision : 2,
32985 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32987 allowNegative : true,
32989 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32991 minValue : Number.NEGATIVE_INFINITY,
32993 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32995 maxValue : Number.MAX_VALUE,
32997 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32999 minText : "The minimum value for this field is {0}",
33001 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33003 maxText : "The maximum value for this field is {0}",
33005 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33006 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33008 nanText : "{0} is not a valid number",
33010 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33015 initEvents : function()
33017 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33019 var allowed = "0123456789";
33021 if(this.allowDecimals){
33022 allowed += this.decimalSeparator;
33025 if(this.allowNegative){
33029 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33031 var keyPress = function(e){
33033 var k = e.getKey();
33035 var c = e.getCharCode();
33038 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33039 allowed.indexOf(String.fromCharCode(c)) === -1
33045 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33049 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33054 this.el.on("keypress", keyPress, this);
33057 validateValue : function(value)
33060 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33064 var num = this.parseValue(value);
33067 this.markInvalid(String.format(this.nanText, value));
33071 if(num < this.minValue){
33072 this.markInvalid(String.format(this.minText, this.minValue));
33076 if(num > this.maxValue){
33077 this.markInvalid(String.format(this.maxText, this.maxValue));
33084 getValue : function()
33086 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33089 parseValue : function(value)
33091 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33092 return isNaN(value) ? '' : value;
33095 fixPrecision : function(value)
33097 var nan = isNaN(value);
33099 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33100 return nan ? '' : value;
33102 return parseFloat(value).toFixed(this.decimalPrecision);
33105 setValue : function(v)
33107 v = this.fixPrecision(v);
33108 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33111 decimalPrecisionFcn : function(v)
33113 return Math.floor(v);
33116 beforeBlur : function()
33122 var v = this.parseValue(this.getRawValue());
33137 * @class Roo.bootstrap.DocumentSlider
33138 * @extends Roo.bootstrap.Component
33139 * Bootstrap DocumentSlider class
33142 * Create a new DocumentViewer
33143 * @param {Object} config The config object
33146 Roo.bootstrap.DocumentSlider = function(config){
33147 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33154 * Fire after initEvent
33155 * @param {Roo.bootstrap.DocumentSlider} this
33160 * Fire after update
33161 * @param {Roo.bootstrap.DocumentSlider} this
33167 * @param {Roo.bootstrap.DocumentSlider} this
33173 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33179 getAutoCreate : function()
33183 cls : 'roo-document-slider',
33187 cls : 'roo-document-slider-header',
33191 cls : 'roo-document-slider-header-title'
33197 cls : 'roo-document-slider-body',
33201 cls : 'roo-document-slider-prev',
33205 cls : 'fa fa-chevron-left'
33211 cls : 'roo-document-slider-thumb',
33215 cls : 'roo-document-slider-image'
33221 cls : 'roo-document-slider-next',
33225 cls : 'fa fa-chevron-right'
33237 initEvents : function()
33239 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33240 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33242 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33243 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33245 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33246 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33248 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33249 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33251 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33252 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33254 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33255 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33257 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33258 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33260 this.thumbEl.on('click', this.onClick, this);
33262 this.prevIndicator.on('click', this.prev, this);
33264 this.nextIndicator.on('click', this.next, this);
33268 initial : function()
33270 if(this.files.length){
33271 this.indicator = 1;
33275 this.fireEvent('initial', this);
33278 update : function()
33280 this.imageEl.attr('src', this.files[this.indicator - 1]);
33282 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33284 this.prevIndicator.show();
33286 if(this.indicator == 1){
33287 this.prevIndicator.hide();
33290 this.nextIndicator.show();
33292 if(this.indicator == this.files.length){
33293 this.nextIndicator.hide();
33296 this.thumbEl.scrollTo('top');
33298 this.fireEvent('update', this);
33301 onClick : function(e)
33303 e.preventDefault();
33305 this.fireEvent('click', this);
33310 e.preventDefault();
33312 this.indicator = Math.max(1, this.indicator - 1);
33319 e.preventDefault();
33321 this.indicator = Math.min(this.files.length, this.indicator + 1);
33335 * @class Roo.bootstrap.RadioSet
33336 * @extends Roo.bootstrap.Input
33337 * Bootstrap RadioSet class
33338 * @cfg {String} indicatorpos (left|right) default left
33339 * @cfg {Boolean} inline (true|false) inline the element (default true)
33340 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33342 * Create a new RadioSet
33343 * @param {Object} config The config object
33346 Roo.bootstrap.RadioSet = function(config){
33348 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33352 Roo.bootstrap.RadioSet.register(this);
33357 * Fires when the element is checked or unchecked.
33358 * @param {Roo.bootstrap.RadioSet} this This radio
33359 * @param {Roo.bootstrap.Radio} item The checked item
33366 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33374 indicatorpos : 'left',
33376 getAutoCreate : function()
33380 cls : 'roo-radio-set-label',
33384 html : this.fieldLabel
33389 if(this.indicatorpos == 'left'){
33392 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33393 tooltip : 'This field is required'
33398 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33399 tooltip : 'This field is required'
33405 cls : 'roo-radio-set-items'
33408 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33410 if (align === 'left' && this.fieldLabel.length) {
33413 cls : "roo-radio-set-right",
33419 if(this.labelWidth > 12){
33420 label.style = "width: " + this.labelWidth + 'px';
33423 if(this.labelWidth < 13 && this.labelmd == 0){
33424 this.labelmd = this.labelWidth;
33427 if(this.labellg > 0){
33428 label.cls += ' col-lg-' + this.labellg;
33429 items.cls += ' col-lg-' + (12 - this.labellg);
33432 if(this.labelmd > 0){
33433 label.cls += ' col-md-' + this.labelmd;
33434 items.cls += ' col-md-' + (12 - this.labelmd);
33437 if(this.labelsm > 0){
33438 label.cls += ' col-sm-' + this.labelsm;
33439 items.cls += ' col-sm-' + (12 - this.labelsm);
33442 if(this.labelxs > 0){
33443 label.cls += ' col-xs-' + this.labelxs;
33444 items.cls += ' col-xs-' + (12 - this.labelxs);
33450 cls : 'roo-radio-set',
33454 cls : 'roo-radio-set-input',
33457 value : this.value ? this.value : ''
33464 if(this.weight.length){
33465 cfg.cls += ' roo-radio-' + this.weight;
33469 cfg.cls += ' roo-radio-set-inline';
33473 ['xs','sm','md','lg'].map(function(size){
33474 if (settings[size]) {
33475 cfg.cls += ' col-' + size + '-' + settings[size];
33483 initEvents : function()
33485 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33486 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33488 if(!this.fieldLabel.length){
33489 this.labelEl.hide();
33492 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33493 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33495 this.indicatorEl().addClass('invisible');
33497 this.originalValue = this.getValue();
33501 inputEl: function ()
33503 return this.el.select('.roo-radio-set-input', true).first();
33506 getChildContainer : function()
33508 return this.itemsEl;
33511 register : function(item)
33513 this.radioes.push(item);
33517 validate : function()
33521 Roo.each(this.radioes, function(i){
33530 if(this.allowBlank) {
33534 if(this.disabled || valid){
33539 this.markInvalid();
33544 markValid : function()
33546 if(this.labelEl.isVisible(true)){
33547 this.indicatorEl().removeClass('visible');
33548 this.indicatorEl().addClass('invisible');
33551 this.el.removeClass([this.invalidClass, this.validClass]);
33552 this.el.addClass(this.validClass);
33554 this.fireEvent('valid', this);
33557 markInvalid : function(msg)
33559 if(this.allowBlank || this.disabled){
33563 if(this.labelEl.isVisible(true)){
33564 this.indicatorEl().removeClass('invisible');
33565 this.indicatorEl().addClass('visible');
33568 this.el.removeClass([this.invalidClass, this.validClass]);
33569 this.el.addClass(this.invalidClass);
33571 this.fireEvent('invalid', this, msg);
33575 setValue : function(v, suppressEvent)
33577 if(this.value === v){
33584 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33587 Roo.each(this.radioes, function(i){
33590 i.el.removeClass('checked');
33592 if(i.value === v || i.value.toString() === v.toString()){
33594 i.el.addClass('checked');
33596 if(suppressEvent !== true){
33597 this.fireEvent('check', this, i);
33606 clearInvalid : function(){
33608 if(!this.el || this.preventMark){
33612 this.el.removeClass([this.invalidClass]);
33614 this.fireEvent('valid', this);
33619 Roo.apply(Roo.bootstrap.RadioSet, {
33623 register : function(set)
33625 this.groups[set.name] = set;
33628 get: function(name)
33630 if (typeof(this.groups[name]) == 'undefined') {
33634 return this.groups[name] ;
33640 * Ext JS Library 1.1.1
33641 * Copyright(c) 2006-2007, Ext JS, LLC.
33643 * Originally Released Under LGPL - original licence link has changed is not relivant.
33646 * <script type="text/javascript">
33651 * @class Roo.bootstrap.SplitBar
33652 * @extends Roo.util.Observable
33653 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33657 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33658 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33659 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33660 split.minSize = 100;
33661 split.maxSize = 600;
33662 split.animate = true;
33663 split.on('moved', splitterMoved);
33666 * Create a new SplitBar
33667 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33668 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33669 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33670 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33671 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33672 position of the SplitBar).
33674 Roo.bootstrap.SplitBar = function(cfg){
33679 // dragElement : elm
33680 // resizingElement: el,
33682 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33683 // placement : Roo.bootstrap.SplitBar.LEFT ,
33684 // existingProxy ???
33687 this.el = Roo.get(cfg.dragElement, true);
33688 this.el.dom.unselectable = "on";
33690 this.resizingEl = Roo.get(cfg.resizingElement, true);
33694 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33695 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33698 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33701 * The minimum size of the resizing element. (Defaults to 0)
33707 * The maximum size of the resizing element. (Defaults to 2000)
33710 this.maxSize = 2000;
33713 * Whether to animate the transition to the new size
33716 this.animate = false;
33719 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33722 this.useShim = false;
33727 if(!cfg.existingProxy){
33729 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33731 this.proxy = Roo.get(cfg.existingProxy).dom;
33734 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33737 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33740 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33743 this.dragSpecs = {};
33746 * @private The adapter to use to positon and resize elements
33748 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33749 this.adapter.init(this);
33751 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33753 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33754 this.el.addClass("roo-splitbar-h");
33757 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33758 this.el.addClass("roo-splitbar-v");
33764 * Fires when the splitter is moved (alias for {@link #event-moved})
33765 * @param {Roo.bootstrap.SplitBar} this
33766 * @param {Number} newSize the new width or height
33771 * Fires when the splitter is moved
33772 * @param {Roo.bootstrap.SplitBar} this
33773 * @param {Number} newSize the new width or height
33777 * @event beforeresize
33778 * Fires before the splitter is dragged
33779 * @param {Roo.bootstrap.SplitBar} this
33781 "beforeresize" : true,
33783 "beforeapply" : true
33786 Roo.util.Observable.call(this);
33789 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33790 onStartProxyDrag : function(x, y){
33791 this.fireEvent("beforeresize", this);
33793 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33795 o.enableDisplayMode("block");
33796 // all splitbars share the same overlay
33797 Roo.bootstrap.SplitBar.prototype.overlay = o;
33799 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33800 this.overlay.show();
33801 Roo.get(this.proxy).setDisplayed("block");
33802 var size = this.adapter.getElementSize(this);
33803 this.activeMinSize = this.getMinimumSize();;
33804 this.activeMaxSize = this.getMaximumSize();;
33805 var c1 = size - this.activeMinSize;
33806 var c2 = Math.max(this.activeMaxSize - size, 0);
33807 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33808 this.dd.resetConstraints();
33809 this.dd.setXConstraint(
33810 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33811 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33813 this.dd.setYConstraint(0, 0);
33815 this.dd.resetConstraints();
33816 this.dd.setXConstraint(0, 0);
33817 this.dd.setYConstraint(
33818 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33819 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33822 this.dragSpecs.startSize = size;
33823 this.dragSpecs.startPoint = [x, y];
33824 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33828 * @private Called after the drag operation by the DDProxy
33830 onEndProxyDrag : function(e){
33831 Roo.get(this.proxy).setDisplayed(false);
33832 var endPoint = Roo.lib.Event.getXY(e);
33834 this.overlay.hide();
33837 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33838 newSize = this.dragSpecs.startSize +
33839 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33840 endPoint[0] - this.dragSpecs.startPoint[0] :
33841 this.dragSpecs.startPoint[0] - endPoint[0]
33844 newSize = this.dragSpecs.startSize +
33845 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33846 endPoint[1] - this.dragSpecs.startPoint[1] :
33847 this.dragSpecs.startPoint[1] - endPoint[1]
33850 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33851 if(newSize != this.dragSpecs.startSize){
33852 if(this.fireEvent('beforeapply', this, newSize) !== false){
33853 this.adapter.setElementSize(this, newSize);
33854 this.fireEvent("moved", this, newSize);
33855 this.fireEvent("resize", this, newSize);
33861 * Get the adapter this SplitBar uses
33862 * @return The adapter object
33864 getAdapter : function(){
33865 return this.adapter;
33869 * Set the adapter this SplitBar uses
33870 * @param {Object} adapter A SplitBar adapter object
33872 setAdapter : function(adapter){
33873 this.adapter = adapter;
33874 this.adapter.init(this);
33878 * Gets the minimum size for the resizing element
33879 * @return {Number} The minimum size
33881 getMinimumSize : function(){
33882 return this.minSize;
33886 * Sets the minimum size for the resizing element
33887 * @param {Number} minSize The minimum size
33889 setMinimumSize : function(minSize){
33890 this.minSize = minSize;
33894 * Gets the maximum size for the resizing element
33895 * @return {Number} The maximum size
33897 getMaximumSize : function(){
33898 return this.maxSize;
33902 * Sets the maximum size for the resizing element
33903 * @param {Number} maxSize The maximum size
33905 setMaximumSize : function(maxSize){
33906 this.maxSize = maxSize;
33910 * Sets the initialize size for the resizing element
33911 * @param {Number} size The initial size
33913 setCurrentSize : function(size){
33914 var oldAnimate = this.animate;
33915 this.animate = false;
33916 this.adapter.setElementSize(this, size);
33917 this.animate = oldAnimate;
33921 * Destroy this splitbar.
33922 * @param {Boolean} removeEl True to remove the element
33924 destroy : function(removeEl){
33926 this.shim.remove();
33929 this.proxy.parentNode.removeChild(this.proxy);
33937 * @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.
33939 Roo.bootstrap.SplitBar.createProxy = function(dir){
33940 var proxy = new Roo.Element(document.createElement("div"));
33941 proxy.unselectable();
33942 var cls = 'roo-splitbar-proxy';
33943 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33944 document.body.appendChild(proxy.dom);
33949 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33950 * Default Adapter. It assumes the splitter and resizing element are not positioned
33951 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33953 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33956 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33957 // do nothing for now
33958 init : function(s){
33962 * Called before drag operations to get the current size of the resizing element.
33963 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33965 getElementSize : function(s){
33966 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33967 return s.resizingEl.getWidth();
33969 return s.resizingEl.getHeight();
33974 * Called after drag operations to set the size of the resizing element.
33975 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33976 * @param {Number} newSize The new size to set
33977 * @param {Function} onComplete A function to be invoked when resizing is complete
33979 setElementSize : function(s, newSize, onComplete){
33980 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33982 s.resizingEl.setWidth(newSize);
33984 onComplete(s, newSize);
33987 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33992 s.resizingEl.setHeight(newSize);
33994 onComplete(s, newSize);
33997 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34004 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34005 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34006 * Adapter that moves the splitter element to align with the resized sizing element.
34007 * Used with an absolute positioned SplitBar.
34008 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34009 * document.body, make sure you assign an id to the body element.
34011 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34012 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34013 this.container = Roo.get(container);
34016 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34017 init : function(s){
34018 this.basic.init(s);
34021 getElementSize : function(s){
34022 return this.basic.getElementSize(s);
34025 setElementSize : function(s, newSize, onComplete){
34026 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34029 moveSplitter : function(s){
34030 var yes = Roo.bootstrap.SplitBar;
34031 switch(s.placement){
34033 s.el.setX(s.resizingEl.getRight());
34036 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34039 s.el.setY(s.resizingEl.getBottom());
34042 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34049 * Orientation constant - Create a vertical SplitBar
34053 Roo.bootstrap.SplitBar.VERTICAL = 1;
34056 * Orientation constant - Create a horizontal SplitBar
34060 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34063 * Placement constant - The resizing element is to the left of the splitter element
34067 Roo.bootstrap.SplitBar.LEFT = 1;
34070 * Placement constant - The resizing element is to the right of the splitter element
34074 Roo.bootstrap.SplitBar.RIGHT = 2;
34077 * Placement constant - The resizing element is positioned above the splitter element
34081 Roo.bootstrap.SplitBar.TOP = 3;
34084 * Placement constant - The resizing element is positioned under splitter element
34088 Roo.bootstrap.SplitBar.BOTTOM = 4;
34089 Roo.namespace("Roo.bootstrap.layout");/*
34091 * Ext JS Library 1.1.1
34092 * Copyright(c) 2006-2007, Ext JS, LLC.
34094 * Originally Released Under LGPL - original licence link has changed is not relivant.
34097 * <script type="text/javascript">
34101 * @class Roo.bootstrap.layout.Manager
34102 * @extends Roo.bootstrap.Component
34103 * Base class for layout managers.
34105 Roo.bootstrap.layout.Manager = function(config)
34107 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34113 /** false to disable window resize monitoring @type Boolean */
34114 this.monitorWindowResize = true;
34119 * Fires when a layout is performed.
34120 * @param {Roo.LayoutManager} this
34124 * @event regionresized
34125 * Fires when the user resizes a region.
34126 * @param {Roo.LayoutRegion} region The resized region
34127 * @param {Number} newSize The new size (width for east/west, height for north/south)
34129 "regionresized" : true,
34131 * @event regioncollapsed
34132 * Fires when a region is collapsed.
34133 * @param {Roo.LayoutRegion} region The collapsed region
34135 "regioncollapsed" : true,
34137 * @event regionexpanded
34138 * Fires when a region is expanded.
34139 * @param {Roo.LayoutRegion} region The expanded region
34141 "regionexpanded" : true
34143 this.updating = false;
34146 this.el = Roo.get(config.el);
34152 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34157 monitorWindowResize : true,
34163 onRender : function(ct, position)
34166 this.el = Roo.get(ct);
34169 //this.fireEvent('render',this);
34173 initEvents: function()
34177 // ie scrollbar fix
34178 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34179 document.body.scroll = "no";
34180 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34181 this.el.position('relative');
34183 this.id = this.el.id;
34184 this.el.addClass("roo-layout-container");
34185 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34186 if(this.el.dom != document.body ) {
34187 this.el.on('resize', this.layout,this);
34188 this.el.on('show', this.layout,this);
34194 * Returns true if this layout is currently being updated
34195 * @return {Boolean}
34197 isUpdating : function(){
34198 return this.updating;
34202 * Suspend the LayoutManager from doing auto-layouts while
34203 * making multiple add or remove calls
34205 beginUpdate : function(){
34206 this.updating = true;
34210 * Restore auto-layouts and optionally disable the manager from performing a layout
34211 * @param {Boolean} noLayout true to disable a layout update
34213 endUpdate : function(noLayout){
34214 this.updating = false;
34220 layout: function(){
34224 onRegionResized : function(region, newSize){
34225 this.fireEvent("regionresized", region, newSize);
34229 onRegionCollapsed : function(region){
34230 this.fireEvent("regioncollapsed", region);
34233 onRegionExpanded : function(region){
34234 this.fireEvent("regionexpanded", region);
34238 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34239 * performs box-model adjustments.
34240 * @return {Object} The size as an object {width: (the width), height: (the height)}
34242 getViewSize : function()
34245 if(this.el.dom != document.body){
34246 size = this.el.getSize();
34248 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34250 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34251 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34256 * Returns the Element this layout is bound to.
34257 * @return {Roo.Element}
34259 getEl : function(){
34264 * Returns the specified region.
34265 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34266 * @return {Roo.LayoutRegion}
34268 getRegion : function(target){
34269 return this.regions[target.toLowerCase()];
34272 onWindowResize : function(){
34273 if(this.monitorWindowResize){
34280 * Ext JS Library 1.1.1
34281 * Copyright(c) 2006-2007, Ext JS, LLC.
34283 * Originally Released Under LGPL - original licence link has changed is not relivant.
34286 * <script type="text/javascript">
34289 * @class Roo.bootstrap.layout.Border
34290 * @extends Roo.bootstrap.layout.Manager
34291 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34292 * please see: examples/bootstrap/nested.html<br><br>
34294 <b>The container the layout is rendered into can be either the body element or any other element.
34295 If it is not the body element, the container needs to either be an absolute positioned element,
34296 or you will need to add "position:relative" to the css of the container. You will also need to specify
34297 the container size if it is not the body element.</b>
34300 * Create a new Border
34301 * @param {Object} config Configuration options
34303 Roo.bootstrap.layout.Border = function(config){
34304 config = config || {};
34305 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34309 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34310 if(config[region]){
34311 config[region].region = region;
34312 this.addRegion(config[region]);
34318 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34320 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34322 * Creates and adds a new region if it doesn't already exist.
34323 * @param {String} target The target region key (north, south, east, west or center).
34324 * @param {Object} config The regions config object
34325 * @return {BorderLayoutRegion} The new region
34327 addRegion : function(config)
34329 if(!this.regions[config.region]){
34330 var r = this.factory(config);
34331 this.bindRegion(r);
34333 return this.regions[config.region];
34337 bindRegion : function(r){
34338 this.regions[r.config.region] = r;
34340 r.on("visibilitychange", this.layout, this);
34341 r.on("paneladded", this.layout, this);
34342 r.on("panelremoved", this.layout, this);
34343 r.on("invalidated", this.layout, this);
34344 r.on("resized", this.onRegionResized, this);
34345 r.on("collapsed", this.onRegionCollapsed, this);
34346 r.on("expanded", this.onRegionExpanded, this);
34350 * Performs a layout update.
34352 layout : function()
34354 if(this.updating) {
34358 // render all the rebions if they have not been done alreayd?
34359 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34360 if(this.regions[region] && !this.regions[region].bodyEl){
34361 this.regions[region].onRender(this.el)
34365 var size = this.getViewSize();
34366 var w = size.width;
34367 var h = size.height;
34372 //var x = 0, y = 0;
34374 var rs = this.regions;
34375 var north = rs["north"];
34376 var south = rs["south"];
34377 var west = rs["west"];
34378 var east = rs["east"];
34379 var center = rs["center"];
34380 //if(this.hideOnLayout){ // not supported anymore
34381 //c.el.setStyle("display", "none");
34383 if(north && north.isVisible()){
34384 var b = north.getBox();
34385 var m = north.getMargins();
34386 b.width = w - (m.left+m.right);
34389 centerY = b.height + b.y + m.bottom;
34390 centerH -= centerY;
34391 north.updateBox(this.safeBox(b));
34393 if(south && south.isVisible()){
34394 var b = south.getBox();
34395 var m = south.getMargins();
34396 b.width = w - (m.left+m.right);
34398 var totalHeight = (b.height + m.top + m.bottom);
34399 b.y = h - totalHeight + m.top;
34400 centerH -= totalHeight;
34401 south.updateBox(this.safeBox(b));
34403 if(west && west.isVisible()){
34404 var b = west.getBox();
34405 var m = west.getMargins();
34406 b.height = centerH - (m.top+m.bottom);
34408 b.y = centerY + m.top;
34409 var totalWidth = (b.width + m.left + m.right);
34410 centerX += totalWidth;
34411 centerW -= totalWidth;
34412 west.updateBox(this.safeBox(b));
34414 if(east && east.isVisible()){
34415 var b = east.getBox();
34416 var m = east.getMargins();
34417 b.height = centerH - (m.top+m.bottom);
34418 var totalWidth = (b.width + m.left + m.right);
34419 b.x = w - totalWidth + m.left;
34420 b.y = centerY + m.top;
34421 centerW -= totalWidth;
34422 east.updateBox(this.safeBox(b));
34425 var m = center.getMargins();
34427 x: centerX + m.left,
34428 y: centerY + m.top,
34429 width: centerW - (m.left+m.right),
34430 height: centerH - (m.top+m.bottom)
34432 //if(this.hideOnLayout){
34433 //center.el.setStyle("display", "block");
34435 center.updateBox(this.safeBox(centerBox));
34438 this.fireEvent("layout", this);
34442 safeBox : function(box){
34443 box.width = Math.max(0, box.width);
34444 box.height = Math.max(0, box.height);
34449 * Adds a ContentPanel (or subclass) to this layout.
34450 * @param {String} target The target region key (north, south, east, west or center).
34451 * @param {Roo.ContentPanel} panel The panel to add
34452 * @return {Roo.ContentPanel} The added panel
34454 add : function(target, panel){
34456 target = target.toLowerCase();
34457 return this.regions[target].add(panel);
34461 * Remove a ContentPanel (or subclass) to this layout.
34462 * @param {String} target The target region key (north, south, east, west or center).
34463 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34464 * @return {Roo.ContentPanel} The removed panel
34466 remove : function(target, panel){
34467 target = target.toLowerCase();
34468 return this.regions[target].remove(panel);
34472 * Searches all regions for a panel with the specified id
34473 * @param {String} panelId
34474 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34476 findPanel : function(panelId){
34477 var rs = this.regions;
34478 for(var target in rs){
34479 if(typeof rs[target] != "function"){
34480 var p = rs[target].getPanel(panelId);
34490 * Searches all regions for a panel with the specified id and activates (shows) it.
34491 * @param {String/ContentPanel} panelId The panels id or the panel itself
34492 * @return {Roo.ContentPanel} The shown panel or null
34494 showPanel : function(panelId) {
34495 var rs = this.regions;
34496 for(var target in rs){
34497 var r = rs[target];
34498 if(typeof r != "function"){
34499 if(r.hasPanel(panelId)){
34500 return r.showPanel(panelId);
34508 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34509 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34512 restoreState : function(provider){
34514 provider = Roo.state.Manager;
34516 var sm = new Roo.LayoutStateManager();
34517 sm.init(this, provider);
34523 * Adds a xtype elements to the layout.
34527 xtype : 'ContentPanel',
34534 xtype : 'NestedLayoutPanel',
34540 items : [ ... list of content panels or nested layout panels.. ]
34544 * @param {Object} cfg Xtype definition of item to add.
34546 addxtype : function(cfg)
34548 // basically accepts a pannel...
34549 // can accept a layout region..!?!?
34550 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34553 // theory? children can only be panels??
34555 //if (!cfg.xtype.match(/Panel$/)) {
34560 if (typeof(cfg.region) == 'undefined') {
34561 Roo.log("Failed to add Panel, region was not set");
34565 var region = cfg.region;
34571 xitems = cfg.items;
34578 case 'Content': // ContentPanel (el, cfg)
34579 case 'Scroll': // ContentPanel (el, cfg)
34581 cfg.autoCreate = true;
34582 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34584 // var el = this.el.createChild();
34585 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34588 this.add(region, ret);
34592 case 'TreePanel': // our new panel!
34593 cfg.el = this.el.createChild();
34594 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34595 this.add(region, ret);
34600 // create a new Layout (which is a Border Layout...
34602 var clayout = cfg.layout;
34603 clayout.el = this.el.createChild();
34604 clayout.items = clayout.items || [];
34608 // replace this exitems with the clayout ones..
34609 xitems = clayout.items;
34611 // force background off if it's in center...
34612 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34613 cfg.background = false;
34615 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34618 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34619 //console.log('adding nested layout panel ' + cfg.toSource());
34620 this.add(region, ret);
34621 nb = {}; /// find first...
34626 // needs grid and region
34628 //var el = this.getRegion(region).el.createChild();
34630 *var el = this.el.createChild();
34631 // create the grid first...
34632 cfg.grid.container = el;
34633 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34636 if (region == 'center' && this.active ) {
34637 cfg.background = false;
34640 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34642 this.add(region, ret);
34644 if (cfg.background) {
34645 // render grid on panel activation (if panel background)
34646 ret.on('activate', function(gp) {
34647 if (!gp.grid.rendered) {
34648 // gp.grid.render(el);
34652 // cfg.grid.render(el);
34658 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34659 // it was the old xcomponent building that caused this before.
34660 // espeically if border is the top element in the tree.
34670 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34672 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34673 this.add(region, ret);
34677 throw "Can not add '" + cfg.xtype + "' to Border";
34683 this.beginUpdate();
34687 Roo.each(xitems, function(i) {
34688 region = nb && i.region ? i.region : false;
34690 var add = ret.addxtype(i);
34693 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34694 if (!i.background) {
34695 abn[region] = nb[region] ;
34702 // make the last non-background panel active..
34703 //if (nb) { Roo.log(abn); }
34706 for(var r in abn) {
34707 region = this.getRegion(r);
34709 // tried using nb[r], but it does not work..
34711 region.showPanel(abn[r]);
34722 factory : function(cfg)
34725 var validRegions = Roo.bootstrap.layout.Border.regions;
34727 var target = cfg.region;
34730 var r = Roo.bootstrap.layout;
34734 return new r.North(cfg);
34736 return new r.South(cfg);
34738 return new r.East(cfg);
34740 return new r.West(cfg);
34742 return new r.Center(cfg);
34744 throw 'Layout region "'+target+'" not supported.';
34751 * Ext JS Library 1.1.1
34752 * Copyright(c) 2006-2007, Ext JS, LLC.
34754 * Originally Released Under LGPL - original licence link has changed is not relivant.
34757 * <script type="text/javascript">
34761 * @class Roo.bootstrap.layout.Basic
34762 * @extends Roo.util.Observable
34763 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34764 * and does not have a titlebar, tabs or any other features. All it does is size and position
34765 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34766 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34767 * @cfg {string} region the region that it inhabits..
34768 * @cfg {bool} skipConfig skip config?
34772 Roo.bootstrap.layout.Basic = function(config){
34774 this.mgr = config.mgr;
34776 this.position = config.region;
34778 var skipConfig = config.skipConfig;
34782 * @scope Roo.BasicLayoutRegion
34786 * @event beforeremove
34787 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34788 * @param {Roo.LayoutRegion} this
34789 * @param {Roo.ContentPanel} panel The panel
34790 * @param {Object} e The cancel event object
34792 "beforeremove" : true,
34794 * @event invalidated
34795 * Fires when the layout for this region is changed.
34796 * @param {Roo.LayoutRegion} this
34798 "invalidated" : true,
34800 * @event visibilitychange
34801 * Fires when this region is shown or hidden
34802 * @param {Roo.LayoutRegion} this
34803 * @param {Boolean} visibility true or false
34805 "visibilitychange" : true,
34807 * @event paneladded
34808 * Fires when a panel is added.
34809 * @param {Roo.LayoutRegion} this
34810 * @param {Roo.ContentPanel} panel The panel
34812 "paneladded" : true,
34814 * @event panelremoved
34815 * Fires when a panel is removed.
34816 * @param {Roo.LayoutRegion} this
34817 * @param {Roo.ContentPanel} panel The panel
34819 "panelremoved" : true,
34821 * @event beforecollapse
34822 * Fires when this region before collapse.
34823 * @param {Roo.LayoutRegion} this
34825 "beforecollapse" : true,
34828 * Fires when this region is collapsed.
34829 * @param {Roo.LayoutRegion} this
34831 "collapsed" : true,
34834 * Fires when this region is expanded.
34835 * @param {Roo.LayoutRegion} this
34840 * Fires when this region is slid into view.
34841 * @param {Roo.LayoutRegion} this
34843 "slideshow" : true,
34846 * Fires when this region slides out of view.
34847 * @param {Roo.LayoutRegion} this
34849 "slidehide" : true,
34851 * @event panelactivated
34852 * Fires when a panel is activated.
34853 * @param {Roo.LayoutRegion} this
34854 * @param {Roo.ContentPanel} panel The activated panel
34856 "panelactivated" : true,
34859 * Fires when the user resizes this region.
34860 * @param {Roo.LayoutRegion} this
34861 * @param {Number} newSize The new size (width for east/west, height for north/south)
34865 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34866 this.panels = new Roo.util.MixedCollection();
34867 this.panels.getKey = this.getPanelId.createDelegate(this);
34869 this.activePanel = null;
34870 // ensure listeners are added...
34872 if (config.listeners || config.events) {
34873 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34874 listeners : config.listeners || {},
34875 events : config.events || {}
34879 if(skipConfig !== true){
34880 this.applyConfig(config);
34884 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34886 getPanelId : function(p){
34890 applyConfig : function(config){
34891 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34892 this.config = config;
34897 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34898 * the width, for horizontal (north, south) the height.
34899 * @param {Number} newSize The new width or height
34901 resizeTo : function(newSize){
34902 var el = this.el ? this.el :
34903 (this.activePanel ? this.activePanel.getEl() : null);
34905 switch(this.position){
34908 el.setWidth(newSize);
34909 this.fireEvent("resized", this, newSize);
34913 el.setHeight(newSize);
34914 this.fireEvent("resized", this, newSize);
34920 getBox : function(){
34921 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34924 getMargins : function(){
34925 return this.margins;
34928 updateBox : function(box){
34930 var el = this.activePanel.getEl();
34931 el.dom.style.left = box.x + "px";
34932 el.dom.style.top = box.y + "px";
34933 this.activePanel.setSize(box.width, box.height);
34937 * Returns the container element for this region.
34938 * @return {Roo.Element}
34940 getEl : function(){
34941 return this.activePanel;
34945 * Returns true if this region is currently visible.
34946 * @return {Boolean}
34948 isVisible : function(){
34949 return this.activePanel ? true : false;
34952 setActivePanel : function(panel){
34953 panel = this.getPanel(panel);
34954 if(this.activePanel && this.activePanel != panel){
34955 this.activePanel.setActiveState(false);
34956 this.activePanel.getEl().setLeftTop(-10000,-10000);
34958 this.activePanel = panel;
34959 panel.setActiveState(true);
34961 panel.setSize(this.box.width, this.box.height);
34963 this.fireEvent("panelactivated", this, panel);
34964 this.fireEvent("invalidated");
34968 * Show the specified panel.
34969 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34970 * @return {Roo.ContentPanel} The shown panel or null
34972 showPanel : function(panel){
34973 panel = this.getPanel(panel);
34975 this.setActivePanel(panel);
34981 * Get the active panel for this region.
34982 * @return {Roo.ContentPanel} The active panel or null
34984 getActivePanel : function(){
34985 return this.activePanel;
34989 * Add the passed ContentPanel(s)
34990 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34991 * @return {Roo.ContentPanel} The panel added (if only one was added)
34993 add : function(panel){
34994 if(arguments.length > 1){
34995 for(var i = 0, len = arguments.length; i < len; i++) {
34996 this.add(arguments[i]);
35000 if(this.hasPanel(panel)){
35001 this.showPanel(panel);
35004 var el = panel.getEl();
35005 if(el.dom.parentNode != this.mgr.el.dom){
35006 this.mgr.el.dom.appendChild(el.dom);
35008 if(panel.setRegion){
35009 panel.setRegion(this);
35011 this.panels.add(panel);
35012 el.setStyle("position", "absolute");
35013 if(!panel.background){
35014 this.setActivePanel(panel);
35015 if(this.config.initialSize && this.panels.getCount()==1){
35016 this.resizeTo(this.config.initialSize);
35019 this.fireEvent("paneladded", this, panel);
35024 * Returns true if the panel is in this region.
35025 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35026 * @return {Boolean}
35028 hasPanel : function(panel){
35029 if(typeof panel == "object"){ // must be panel obj
35030 panel = panel.getId();
35032 return this.getPanel(panel) ? true : false;
35036 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35037 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35038 * @param {Boolean} preservePanel Overrides the config preservePanel option
35039 * @return {Roo.ContentPanel} The panel that was removed
35041 remove : function(panel, preservePanel){
35042 panel = this.getPanel(panel);
35047 this.fireEvent("beforeremove", this, panel, e);
35048 if(e.cancel === true){
35051 var panelId = panel.getId();
35052 this.panels.removeKey(panelId);
35057 * Returns the panel specified or null if it's not in this region.
35058 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35059 * @return {Roo.ContentPanel}
35061 getPanel : function(id){
35062 if(typeof id == "object"){ // must be panel obj
35065 return this.panels.get(id);
35069 * Returns this regions position (north/south/east/west/center).
35072 getPosition: function(){
35073 return this.position;
35077 * Ext JS Library 1.1.1
35078 * Copyright(c) 2006-2007, Ext JS, LLC.
35080 * Originally Released Under LGPL - original licence link has changed is not relivant.
35083 * <script type="text/javascript">
35087 * @class Roo.bootstrap.layout.Region
35088 * @extends Roo.bootstrap.layout.Basic
35089 * This class represents a region in a layout manager.
35091 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35092 * @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})
35093 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35094 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35095 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35096 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35097 * @cfg {String} title The title for the region (overrides panel titles)
35098 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35099 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35100 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35101 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35102 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35103 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35104 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35105 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35106 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35107 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35109 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35110 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35111 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35112 * @cfg {Number} width For East/West panels
35113 * @cfg {Number} height For North/South panels
35114 * @cfg {Boolean} split To show the splitter
35115 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35117 * @cfg {string} cls Extra CSS classes to add to region
35119 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35120 * @cfg {string} region the region that it inhabits..
35123 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35124 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35126 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35127 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35128 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35130 Roo.bootstrap.layout.Region = function(config)
35132 this.applyConfig(config);
35134 var mgr = config.mgr;
35135 var pos = config.region;
35136 config.skipConfig = true;
35137 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35140 this.onRender(mgr.el);
35143 this.visible = true;
35144 this.collapsed = false;
35145 this.unrendered_panels = [];
35148 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35150 position: '', // set by wrapper (eg. north/south etc..)
35151 unrendered_panels : null, // unrendered panels.
35152 createBody : function(){
35153 /** This region's body element
35154 * @type Roo.Element */
35155 this.bodyEl = this.el.createChild({
35157 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35161 onRender: function(ctr, pos)
35163 var dh = Roo.DomHelper;
35164 /** This region's container element
35165 * @type Roo.Element */
35166 this.el = dh.append(ctr.dom, {
35168 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35170 /** This region's title element
35171 * @type Roo.Element */
35173 this.titleEl = dh.append(this.el.dom,
35176 unselectable: "on",
35177 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35179 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35180 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35183 this.titleEl.enableDisplayMode();
35184 /** This region's title text element
35185 * @type HTMLElement */
35186 this.titleTextEl = this.titleEl.dom.firstChild;
35187 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35189 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35190 this.closeBtn.enableDisplayMode();
35191 this.closeBtn.on("click", this.closeClicked, this);
35192 this.closeBtn.hide();
35194 this.createBody(this.config);
35195 if(this.config.hideWhenEmpty){
35197 this.on("paneladded", this.validateVisibility, this);
35198 this.on("panelremoved", this.validateVisibility, this);
35200 if(this.autoScroll){
35201 this.bodyEl.setStyle("overflow", "auto");
35203 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35205 //if(c.titlebar !== false){
35206 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35207 this.titleEl.hide();
35209 this.titleEl.show();
35210 if(this.config.title){
35211 this.titleTextEl.innerHTML = this.config.title;
35215 if(this.config.collapsed){
35216 this.collapse(true);
35218 if(this.config.hidden){
35222 if (this.unrendered_panels && this.unrendered_panels.length) {
35223 for (var i =0;i< this.unrendered_panels.length; i++) {
35224 this.add(this.unrendered_panels[i]);
35226 this.unrendered_panels = null;
35232 applyConfig : function(c)
35235 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35236 var dh = Roo.DomHelper;
35237 if(c.titlebar !== false){
35238 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35239 this.collapseBtn.on("click", this.collapse, this);
35240 this.collapseBtn.enableDisplayMode();
35242 if(c.showPin === true || this.showPin){
35243 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35244 this.stickBtn.enableDisplayMode();
35245 this.stickBtn.on("click", this.expand, this);
35246 this.stickBtn.hide();
35251 /** This region's collapsed element
35252 * @type Roo.Element */
35255 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35256 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35259 if(c.floatable !== false){
35260 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35261 this.collapsedEl.on("click", this.collapseClick, this);
35264 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35265 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35266 id: "message", unselectable: "on", style:{"float":"left"}});
35267 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35269 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35270 this.expandBtn.on("click", this.expand, this);
35274 if(this.collapseBtn){
35275 this.collapseBtn.setVisible(c.collapsible == true);
35278 this.cmargins = c.cmargins || this.cmargins ||
35279 (this.position == "west" || this.position == "east" ?
35280 {top: 0, left: 2, right:2, bottom: 0} :
35281 {top: 2, left: 0, right:0, bottom: 2});
35283 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35286 this.bottomTabs = c.tabPosition != "top";
35288 this.autoScroll = c.autoScroll || false;
35293 this.duration = c.duration || .30;
35294 this.slideDuration = c.slideDuration || .45;
35299 * Returns true if this region is currently visible.
35300 * @return {Boolean}
35302 isVisible : function(){
35303 return this.visible;
35307 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35308 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35310 //setCollapsedTitle : function(title){
35311 // title = title || " ";
35312 // if(this.collapsedTitleTextEl){
35313 // this.collapsedTitleTextEl.innerHTML = title;
35317 getBox : function(){
35319 // if(!this.collapsed){
35320 b = this.el.getBox(false, true);
35322 // b = this.collapsedEl.getBox(false, true);
35327 getMargins : function(){
35328 return this.margins;
35329 //return this.collapsed ? this.cmargins : this.margins;
35332 highlight : function(){
35333 this.el.addClass("x-layout-panel-dragover");
35336 unhighlight : function(){
35337 this.el.removeClass("x-layout-panel-dragover");
35340 updateBox : function(box)
35342 if (!this.bodyEl) {
35343 return; // not rendered yet..
35347 if(!this.collapsed){
35348 this.el.dom.style.left = box.x + "px";
35349 this.el.dom.style.top = box.y + "px";
35350 this.updateBody(box.width, box.height);
35352 this.collapsedEl.dom.style.left = box.x + "px";
35353 this.collapsedEl.dom.style.top = box.y + "px";
35354 this.collapsedEl.setSize(box.width, box.height);
35357 this.tabs.autoSizeTabs();
35361 updateBody : function(w, h)
35364 this.el.setWidth(w);
35365 w -= this.el.getBorderWidth("rl");
35366 if(this.config.adjustments){
35367 w += this.config.adjustments[0];
35370 if(h !== null && h > 0){
35371 this.el.setHeight(h);
35372 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35373 h -= this.el.getBorderWidth("tb");
35374 if(this.config.adjustments){
35375 h += this.config.adjustments[1];
35377 this.bodyEl.setHeight(h);
35379 h = this.tabs.syncHeight(h);
35382 if(this.panelSize){
35383 w = w !== null ? w : this.panelSize.width;
35384 h = h !== null ? h : this.panelSize.height;
35386 if(this.activePanel){
35387 var el = this.activePanel.getEl();
35388 w = w !== null ? w : el.getWidth();
35389 h = h !== null ? h : el.getHeight();
35390 this.panelSize = {width: w, height: h};
35391 this.activePanel.setSize(w, h);
35393 if(Roo.isIE && this.tabs){
35394 this.tabs.el.repaint();
35399 * Returns the container element for this region.
35400 * @return {Roo.Element}
35402 getEl : function(){
35407 * Hides this region.
35410 //if(!this.collapsed){
35411 this.el.dom.style.left = "-2000px";
35414 // this.collapsedEl.dom.style.left = "-2000px";
35415 // this.collapsedEl.hide();
35417 this.visible = false;
35418 this.fireEvent("visibilitychange", this, false);
35422 * Shows this region if it was previously hidden.
35425 //if(!this.collapsed){
35428 // this.collapsedEl.show();
35430 this.visible = true;
35431 this.fireEvent("visibilitychange", this, true);
35434 closeClicked : function(){
35435 if(this.activePanel){
35436 this.remove(this.activePanel);
35440 collapseClick : function(e){
35442 e.stopPropagation();
35445 e.stopPropagation();
35451 * Collapses this region.
35452 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35455 collapse : function(skipAnim, skipCheck = false){
35456 if(this.collapsed) {
35460 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35462 this.collapsed = true;
35464 this.split.el.hide();
35466 if(this.config.animate && skipAnim !== true){
35467 this.fireEvent("invalidated", this);
35468 this.animateCollapse();
35470 this.el.setLocation(-20000,-20000);
35472 this.collapsedEl.show();
35473 this.fireEvent("collapsed", this);
35474 this.fireEvent("invalidated", this);
35480 animateCollapse : function(){
35485 * Expands this region if it was previously collapsed.
35486 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35487 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35490 expand : function(e, skipAnim){
35492 e.stopPropagation();
35494 if(!this.collapsed || this.el.hasActiveFx()) {
35498 this.afterSlideIn();
35501 this.collapsed = false;
35502 if(this.config.animate && skipAnim !== true){
35503 this.animateExpand();
35507 this.split.el.show();
35509 this.collapsedEl.setLocation(-2000,-2000);
35510 this.collapsedEl.hide();
35511 this.fireEvent("invalidated", this);
35512 this.fireEvent("expanded", this);
35516 animateExpand : function(){
35520 initTabs : function()
35522 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35524 var ts = new Roo.bootstrap.panel.Tabs({
35525 el: this.bodyEl.dom,
35526 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35527 disableTooltips: this.config.disableTabTips,
35528 toolbar : this.config.toolbar
35531 if(this.config.hideTabs){
35532 ts.stripWrap.setDisplayed(false);
35535 ts.resizeTabs = this.config.resizeTabs === true;
35536 ts.minTabWidth = this.config.minTabWidth || 40;
35537 ts.maxTabWidth = this.config.maxTabWidth || 250;
35538 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35539 ts.monitorResize = false;
35540 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35541 ts.bodyEl.addClass('roo-layout-tabs-body');
35542 this.panels.each(this.initPanelAsTab, this);
35545 initPanelAsTab : function(panel){
35546 var ti = this.tabs.addTab(
35550 this.config.closeOnTab && panel.isClosable(),
35553 if(panel.tabTip !== undefined){
35554 ti.setTooltip(panel.tabTip);
35556 ti.on("activate", function(){
35557 this.setActivePanel(panel);
35560 if(this.config.closeOnTab){
35561 ti.on("beforeclose", function(t, e){
35563 this.remove(panel);
35567 panel.tabItem = ti;
35572 updatePanelTitle : function(panel, title)
35574 if(this.activePanel == panel){
35575 this.updateTitle(title);
35578 var ti = this.tabs.getTab(panel.getEl().id);
35580 if(panel.tabTip !== undefined){
35581 ti.setTooltip(panel.tabTip);
35586 updateTitle : function(title){
35587 if(this.titleTextEl && !this.config.title){
35588 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35592 setActivePanel : function(panel)
35594 panel = this.getPanel(panel);
35595 if(this.activePanel && this.activePanel != panel){
35596 if(this.activePanel.setActiveState(false) === false){
35600 this.activePanel = panel;
35601 panel.setActiveState(true);
35602 if(this.panelSize){
35603 panel.setSize(this.panelSize.width, this.panelSize.height);
35606 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35608 this.updateTitle(panel.getTitle());
35610 this.fireEvent("invalidated", this);
35612 this.fireEvent("panelactivated", this, panel);
35616 * Shows the specified panel.
35617 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35618 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35620 showPanel : function(panel)
35622 panel = this.getPanel(panel);
35625 var tab = this.tabs.getTab(panel.getEl().id);
35626 if(tab.isHidden()){
35627 this.tabs.unhideTab(tab.id);
35631 this.setActivePanel(panel);
35638 * Get the active panel for this region.
35639 * @return {Roo.ContentPanel} The active panel or null
35641 getActivePanel : function(){
35642 return this.activePanel;
35645 validateVisibility : function(){
35646 if(this.panels.getCount() < 1){
35647 this.updateTitle(" ");
35648 this.closeBtn.hide();
35651 if(!this.isVisible()){
35658 * Adds the passed ContentPanel(s) to this region.
35659 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35660 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35662 add : function(panel)
35664 if(arguments.length > 1){
35665 for(var i = 0, len = arguments.length; i < len; i++) {
35666 this.add(arguments[i]);
35671 // if we have not been rendered yet, then we can not really do much of this..
35672 if (!this.bodyEl) {
35673 this.unrendered_panels.push(panel);
35680 if(this.hasPanel(panel)){
35681 this.showPanel(panel);
35684 panel.setRegion(this);
35685 this.panels.add(panel);
35686 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35687 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35688 // and hide them... ???
35689 this.bodyEl.dom.appendChild(panel.getEl().dom);
35690 if(panel.background !== true){
35691 this.setActivePanel(panel);
35693 this.fireEvent("paneladded", this, panel);
35700 this.initPanelAsTab(panel);
35704 if(panel.background !== true){
35705 this.tabs.activate(panel.getEl().id);
35707 this.fireEvent("paneladded", this, panel);
35712 * Hides the tab for the specified panel.
35713 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35715 hidePanel : function(panel){
35716 if(this.tabs && (panel = this.getPanel(panel))){
35717 this.tabs.hideTab(panel.getEl().id);
35722 * Unhides the tab for a previously hidden panel.
35723 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35725 unhidePanel : function(panel){
35726 if(this.tabs && (panel = this.getPanel(panel))){
35727 this.tabs.unhideTab(panel.getEl().id);
35731 clearPanels : function(){
35732 while(this.panels.getCount() > 0){
35733 this.remove(this.panels.first());
35738 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35739 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35740 * @param {Boolean} preservePanel Overrides the config preservePanel option
35741 * @return {Roo.ContentPanel} The panel that was removed
35743 remove : function(panel, preservePanel)
35745 panel = this.getPanel(panel);
35750 this.fireEvent("beforeremove", this, panel, e);
35751 if(e.cancel === true){
35754 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35755 var panelId = panel.getId();
35756 this.panels.removeKey(panelId);
35758 document.body.appendChild(panel.getEl().dom);
35761 this.tabs.removeTab(panel.getEl().id);
35762 }else if (!preservePanel){
35763 this.bodyEl.dom.removeChild(panel.getEl().dom);
35765 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35766 var p = this.panels.first();
35767 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35768 tempEl.appendChild(p.getEl().dom);
35769 this.bodyEl.update("");
35770 this.bodyEl.dom.appendChild(p.getEl().dom);
35772 this.updateTitle(p.getTitle());
35774 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35775 this.setActivePanel(p);
35777 panel.setRegion(null);
35778 if(this.activePanel == panel){
35779 this.activePanel = null;
35781 if(this.config.autoDestroy !== false && preservePanel !== true){
35782 try{panel.destroy();}catch(e){}
35784 this.fireEvent("panelremoved", this, panel);
35789 * Returns the TabPanel component used by this region
35790 * @return {Roo.TabPanel}
35792 getTabs : function(){
35796 createTool : function(parentEl, className){
35797 var btn = Roo.DomHelper.append(parentEl, {
35799 cls: "x-layout-tools-button",
35802 cls: "roo-layout-tools-button-inner " + className,
35806 btn.addClassOnOver("roo-layout-tools-button-over");
35811 * Ext JS Library 1.1.1
35812 * Copyright(c) 2006-2007, Ext JS, LLC.
35814 * Originally Released Under LGPL - original licence link has changed is not relivant.
35817 * <script type="text/javascript">
35823 * @class Roo.SplitLayoutRegion
35824 * @extends Roo.LayoutRegion
35825 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35827 Roo.bootstrap.layout.Split = function(config){
35828 this.cursor = config.cursor;
35829 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35832 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35834 splitTip : "Drag to resize.",
35835 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35836 useSplitTips : false,
35838 applyConfig : function(config){
35839 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35842 onRender : function(ctr,pos) {
35844 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35845 if(!this.config.split){
35850 var splitEl = Roo.DomHelper.append(ctr.dom, {
35852 id: this.el.id + "-split",
35853 cls: "roo-layout-split roo-layout-split-"+this.position,
35856 /** The SplitBar for this region
35857 * @type Roo.SplitBar */
35858 // does not exist yet...
35859 Roo.log([this.position, this.orientation]);
35861 this.split = new Roo.bootstrap.SplitBar({
35862 dragElement : splitEl,
35863 resizingElement: this.el,
35864 orientation : this.orientation
35867 this.split.on("moved", this.onSplitMove, this);
35868 this.split.useShim = this.config.useShim === true;
35869 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35870 if(this.useSplitTips){
35871 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35873 //if(config.collapsible){
35874 // this.split.el.on("dblclick", this.collapse, this);
35877 if(typeof this.config.minSize != "undefined"){
35878 this.split.minSize = this.config.minSize;
35880 if(typeof this.config.maxSize != "undefined"){
35881 this.split.maxSize = this.config.maxSize;
35883 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35884 this.hideSplitter();
35889 getHMaxSize : function(){
35890 var cmax = this.config.maxSize || 10000;
35891 var center = this.mgr.getRegion("center");
35892 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35895 getVMaxSize : function(){
35896 var cmax = this.config.maxSize || 10000;
35897 var center = this.mgr.getRegion("center");
35898 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35901 onSplitMove : function(split, newSize){
35902 this.fireEvent("resized", this, newSize);
35906 * Returns the {@link Roo.SplitBar} for this region.
35907 * @return {Roo.SplitBar}
35909 getSplitBar : function(){
35914 this.hideSplitter();
35915 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35918 hideSplitter : function(){
35920 this.split.el.setLocation(-2000,-2000);
35921 this.split.el.hide();
35927 this.split.el.show();
35929 Roo.bootstrap.layout.Split.superclass.show.call(this);
35932 beforeSlide: function(){
35933 if(Roo.isGecko){// firefox overflow auto bug workaround
35934 this.bodyEl.clip();
35936 this.tabs.bodyEl.clip();
35938 if(this.activePanel){
35939 this.activePanel.getEl().clip();
35941 if(this.activePanel.beforeSlide){
35942 this.activePanel.beforeSlide();
35948 afterSlide : function(){
35949 if(Roo.isGecko){// firefox overflow auto bug workaround
35950 this.bodyEl.unclip();
35952 this.tabs.bodyEl.unclip();
35954 if(this.activePanel){
35955 this.activePanel.getEl().unclip();
35956 if(this.activePanel.afterSlide){
35957 this.activePanel.afterSlide();
35963 initAutoHide : function(){
35964 if(this.autoHide !== false){
35965 if(!this.autoHideHd){
35966 var st = new Roo.util.DelayedTask(this.slideIn, this);
35967 this.autoHideHd = {
35968 "mouseout": function(e){
35969 if(!e.within(this.el, true)){
35973 "mouseover" : function(e){
35979 this.el.on(this.autoHideHd);
35983 clearAutoHide : function(){
35984 if(this.autoHide !== false){
35985 this.el.un("mouseout", this.autoHideHd.mouseout);
35986 this.el.un("mouseover", this.autoHideHd.mouseover);
35990 clearMonitor : function(){
35991 Roo.get(document).un("click", this.slideInIf, this);
35994 // these names are backwards but not changed for compat
35995 slideOut : function(){
35996 if(this.isSlid || this.el.hasActiveFx()){
35999 this.isSlid = true;
36000 if(this.collapseBtn){
36001 this.collapseBtn.hide();
36003 this.closeBtnState = this.closeBtn.getStyle('display');
36004 this.closeBtn.hide();
36006 this.stickBtn.show();
36009 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36010 this.beforeSlide();
36011 this.el.setStyle("z-index", 10001);
36012 this.el.slideIn(this.getSlideAnchor(), {
36013 callback: function(){
36015 this.initAutoHide();
36016 Roo.get(document).on("click", this.slideInIf, this);
36017 this.fireEvent("slideshow", this);
36024 afterSlideIn : function(){
36025 this.clearAutoHide();
36026 this.isSlid = false;
36027 this.clearMonitor();
36028 this.el.setStyle("z-index", "");
36029 if(this.collapseBtn){
36030 this.collapseBtn.show();
36032 this.closeBtn.setStyle('display', this.closeBtnState);
36034 this.stickBtn.hide();
36036 this.fireEvent("slidehide", this);
36039 slideIn : function(cb){
36040 if(!this.isSlid || this.el.hasActiveFx()){
36044 this.isSlid = false;
36045 this.beforeSlide();
36046 this.el.slideOut(this.getSlideAnchor(), {
36047 callback: function(){
36048 this.el.setLeftTop(-10000, -10000);
36050 this.afterSlideIn();
36058 slideInIf : function(e){
36059 if(!e.within(this.el)){
36064 animateCollapse : function(){
36065 this.beforeSlide();
36066 this.el.setStyle("z-index", 20000);
36067 var anchor = this.getSlideAnchor();
36068 this.el.slideOut(anchor, {
36069 callback : function(){
36070 this.el.setStyle("z-index", "");
36071 this.collapsedEl.slideIn(anchor, {duration:.3});
36073 this.el.setLocation(-10000,-10000);
36075 this.fireEvent("collapsed", this);
36082 animateExpand : function(){
36083 this.beforeSlide();
36084 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36085 this.el.setStyle("z-index", 20000);
36086 this.collapsedEl.hide({
36089 this.el.slideIn(this.getSlideAnchor(), {
36090 callback : function(){
36091 this.el.setStyle("z-index", "");
36094 this.split.el.show();
36096 this.fireEvent("invalidated", this);
36097 this.fireEvent("expanded", this);
36125 getAnchor : function(){
36126 return this.anchors[this.position];
36129 getCollapseAnchor : function(){
36130 return this.canchors[this.position];
36133 getSlideAnchor : function(){
36134 return this.sanchors[this.position];
36137 getAlignAdj : function(){
36138 var cm = this.cmargins;
36139 switch(this.position){
36155 getExpandAdj : function(){
36156 var c = this.collapsedEl, cm = this.cmargins;
36157 switch(this.position){
36159 return [-(cm.right+c.getWidth()+cm.left), 0];
36162 return [cm.right+c.getWidth()+cm.left, 0];
36165 return [0, -(cm.top+cm.bottom+c.getHeight())];
36168 return [0, cm.top+cm.bottom+c.getHeight()];
36174 * Ext JS Library 1.1.1
36175 * Copyright(c) 2006-2007, Ext JS, LLC.
36177 * Originally Released Under LGPL - original licence link has changed is not relivant.
36180 * <script type="text/javascript">
36183 * These classes are private internal classes
36185 Roo.bootstrap.layout.Center = function(config){
36186 config.region = "center";
36187 Roo.bootstrap.layout.Region.call(this, config);
36188 this.visible = true;
36189 this.minWidth = config.minWidth || 20;
36190 this.minHeight = config.minHeight || 20;
36193 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36195 // center panel can't be hidden
36199 // center panel can't be hidden
36202 getMinWidth: function(){
36203 return this.minWidth;
36206 getMinHeight: function(){
36207 return this.minHeight;
36220 Roo.bootstrap.layout.North = function(config)
36222 config.region = 'north';
36223 config.cursor = 'n-resize';
36225 Roo.bootstrap.layout.Split.call(this, config);
36229 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36230 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36231 this.split.el.addClass("roo-layout-split-v");
36233 var size = config.initialSize || config.height;
36234 if(typeof size != "undefined"){
36235 this.el.setHeight(size);
36238 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36240 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36244 getBox : function(){
36245 if(this.collapsed){
36246 return this.collapsedEl.getBox();
36248 var box = this.el.getBox();
36250 box.height += this.split.el.getHeight();
36255 updateBox : function(box){
36256 if(this.split && !this.collapsed){
36257 box.height -= this.split.el.getHeight();
36258 this.split.el.setLeft(box.x);
36259 this.split.el.setTop(box.y+box.height);
36260 this.split.el.setWidth(box.width);
36262 if(this.collapsed){
36263 this.updateBody(box.width, null);
36265 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36273 Roo.bootstrap.layout.South = function(config){
36274 config.region = 'south';
36275 config.cursor = 's-resize';
36276 Roo.bootstrap.layout.Split.call(this, config);
36278 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36279 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36280 this.split.el.addClass("roo-layout-split-v");
36282 var size = config.initialSize || config.height;
36283 if(typeof size != "undefined"){
36284 this.el.setHeight(size);
36288 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36289 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36290 getBox : function(){
36291 if(this.collapsed){
36292 return this.collapsedEl.getBox();
36294 var box = this.el.getBox();
36296 var sh = this.split.el.getHeight();
36303 updateBox : function(box){
36304 if(this.split && !this.collapsed){
36305 var sh = this.split.el.getHeight();
36308 this.split.el.setLeft(box.x);
36309 this.split.el.setTop(box.y-sh);
36310 this.split.el.setWidth(box.width);
36312 if(this.collapsed){
36313 this.updateBody(box.width, null);
36315 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36319 Roo.bootstrap.layout.East = function(config){
36320 config.region = "east";
36321 config.cursor = "e-resize";
36322 Roo.bootstrap.layout.Split.call(this, config);
36324 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36325 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36326 this.split.el.addClass("roo-layout-split-h");
36328 var size = config.initialSize || config.width;
36329 if(typeof size != "undefined"){
36330 this.el.setWidth(size);
36333 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36334 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36335 getBox : function(){
36336 if(this.collapsed){
36337 return this.collapsedEl.getBox();
36339 var box = this.el.getBox();
36341 var sw = this.split.el.getWidth();
36348 updateBox : function(box){
36349 if(this.split && !this.collapsed){
36350 var sw = this.split.el.getWidth();
36352 this.split.el.setLeft(box.x);
36353 this.split.el.setTop(box.y);
36354 this.split.el.setHeight(box.height);
36357 if(this.collapsed){
36358 this.updateBody(null, box.height);
36360 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36364 Roo.bootstrap.layout.West = function(config){
36365 config.region = "west";
36366 config.cursor = "w-resize";
36368 Roo.bootstrap.layout.Split.call(this, config);
36370 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36371 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36372 this.split.el.addClass("roo-layout-split-h");
36376 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36377 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36379 onRender: function(ctr, pos)
36381 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36382 var size = this.config.initialSize || this.config.width;
36383 if(typeof size != "undefined"){
36384 this.el.setWidth(size);
36388 getBox : function(){
36389 if(this.collapsed){
36390 return this.collapsedEl.getBox();
36392 var box = this.el.getBox();
36394 box.width += this.split.el.getWidth();
36399 updateBox : function(box){
36400 if(this.split && !this.collapsed){
36401 var sw = this.split.el.getWidth();
36403 this.split.el.setLeft(box.x+box.width);
36404 this.split.el.setTop(box.y);
36405 this.split.el.setHeight(box.height);
36407 if(this.collapsed){
36408 this.updateBody(null, box.height);
36410 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36413 Roo.namespace("Roo.bootstrap.panel");/*
36415 * Ext JS Library 1.1.1
36416 * Copyright(c) 2006-2007, Ext JS, LLC.
36418 * Originally Released Under LGPL - original licence link has changed is not relivant.
36421 * <script type="text/javascript">
36424 * @class Roo.ContentPanel
36425 * @extends Roo.util.Observable
36426 * A basic ContentPanel element.
36427 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36428 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36429 * @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
36430 * @cfg {Boolean} closable True if the panel can be closed/removed
36431 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36432 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36433 * @cfg {Toolbar} toolbar A toolbar for this panel
36434 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36435 * @cfg {String} title The title for this panel
36436 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36437 * @cfg {String} url Calls {@link #setUrl} with this value
36438 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36439 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36440 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36441 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36442 * @cfg {Boolean} badges render the badges
36445 * Create a new ContentPanel.
36446 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36447 * @param {String/Object} config A string to set only the title or a config object
36448 * @param {String} content (optional) Set the HTML content for this panel
36449 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36451 Roo.bootstrap.panel.Content = function( config){
36453 this.tpl = config.tpl || false;
36455 var el = config.el;
36456 var content = config.content;
36458 if(config.autoCreate){ // xtype is available if this is called from factory
36461 this.el = Roo.get(el);
36462 if(!this.el && config && config.autoCreate){
36463 if(typeof config.autoCreate == "object"){
36464 if(!config.autoCreate.id){
36465 config.autoCreate.id = config.id||el;
36467 this.el = Roo.DomHelper.append(document.body,
36468 config.autoCreate, true);
36470 var elcfg = { tag: "div",
36471 cls: "roo-layout-inactive-content",
36475 elcfg.html = config.html;
36479 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36482 this.closable = false;
36483 this.loaded = false;
36484 this.active = false;
36487 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36489 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36491 this.wrapEl = this.el; //this.el.wrap();
36493 if (config.toolbar.items) {
36494 ti = config.toolbar.items ;
36495 delete config.toolbar.items ;
36499 this.toolbar.render(this.wrapEl, 'before');
36500 for(var i =0;i < ti.length;i++) {
36501 // Roo.log(['add child', items[i]]);
36502 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36504 this.toolbar.items = nitems;
36505 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36506 delete config.toolbar;
36510 // xtype created footer. - not sure if will work as we normally have to render first..
36511 if (this.footer && !this.footer.el && this.footer.xtype) {
36512 if (!this.wrapEl) {
36513 this.wrapEl = this.el.wrap();
36516 this.footer.container = this.wrapEl.createChild();
36518 this.footer = Roo.factory(this.footer, Roo);
36523 if(typeof config == "string"){
36524 this.title = config;
36526 Roo.apply(this, config);
36530 this.resizeEl = Roo.get(this.resizeEl, true);
36532 this.resizeEl = this.el;
36534 // handle view.xtype
36542 * Fires when this panel is activated.
36543 * @param {Roo.ContentPanel} this
36547 * @event deactivate
36548 * Fires when this panel is activated.
36549 * @param {Roo.ContentPanel} this
36551 "deactivate" : true,
36555 * Fires when this panel is resized if fitToFrame is true.
36556 * @param {Roo.ContentPanel} this
36557 * @param {Number} width The width after any component adjustments
36558 * @param {Number} height The height after any component adjustments
36564 * Fires when this tab is created
36565 * @param {Roo.ContentPanel} this
36576 if(this.autoScroll){
36577 this.resizeEl.setStyle("overflow", "auto");
36579 // fix randome scrolling
36580 //this.el.on('scroll', function() {
36581 // Roo.log('fix random scolling');
36582 // this.scrollTo('top',0);
36585 content = content || this.content;
36587 this.setContent(content);
36589 if(config && config.url){
36590 this.setUrl(this.url, this.params, this.loadOnce);
36595 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36597 if (this.view && typeof(this.view.xtype) != 'undefined') {
36598 this.view.el = this.el.appendChild(document.createElement("div"));
36599 this.view = Roo.factory(this.view);
36600 this.view.render && this.view.render(false, '');
36604 this.fireEvent('render', this);
36607 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36611 setRegion : function(region){
36612 this.region = region;
36613 this.setActiveClass(region && !this.background);
36617 setActiveClass: function(state)
36620 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36621 this.el.setStyle('position','relative');
36623 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36624 this.el.setStyle('position', 'absolute');
36629 * Returns the toolbar for this Panel if one was configured.
36630 * @return {Roo.Toolbar}
36632 getToolbar : function(){
36633 return this.toolbar;
36636 setActiveState : function(active)
36638 this.active = active;
36639 this.setActiveClass(active);
36641 if(this.fireEvent("deactivate", this) === false){
36646 this.fireEvent("activate", this);
36650 * Updates this panel's element
36651 * @param {String} content The new content
36652 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36654 setContent : function(content, loadScripts){
36655 this.el.update(content, loadScripts);
36658 ignoreResize : function(w, h){
36659 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36662 this.lastSize = {width: w, height: h};
36667 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36668 * @return {Roo.UpdateManager} The UpdateManager
36670 getUpdateManager : function(){
36671 return this.el.getUpdateManager();
36674 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36675 * @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:
36678 url: "your-url.php",
36679 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36680 callback: yourFunction,
36681 scope: yourObject, //(optional scope)
36684 text: "Loading...",
36689 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36690 * 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.
36691 * @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}
36692 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36693 * @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.
36694 * @return {Roo.ContentPanel} this
36697 var um = this.el.getUpdateManager();
36698 um.update.apply(um, arguments);
36704 * 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.
36705 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36706 * @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)
36707 * @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)
36708 * @return {Roo.UpdateManager} The UpdateManager
36710 setUrl : function(url, params, loadOnce){
36711 if(this.refreshDelegate){
36712 this.removeListener("activate", this.refreshDelegate);
36714 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36715 this.on("activate", this.refreshDelegate);
36716 return this.el.getUpdateManager();
36719 _handleRefresh : function(url, params, loadOnce){
36720 if(!loadOnce || !this.loaded){
36721 var updater = this.el.getUpdateManager();
36722 updater.update(url, params, this._setLoaded.createDelegate(this));
36726 _setLoaded : function(){
36727 this.loaded = true;
36731 * Returns this panel's id
36734 getId : function(){
36739 * Returns this panel's element - used by regiosn to add.
36740 * @return {Roo.Element}
36742 getEl : function(){
36743 return this.wrapEl || this.el;
36748 adjustForComponents : function(width, height)
36750 //Roo.log('adjustForComponents ');
36751 if(this.resizeEl != this.el){
36752 width -= this.el.getFrameWidth('lr');
36753 height -= this.el.getFrameWidth('tb');
36756 var te = this.toolbar.getEl();
36757 te.setWidth(width);
36758 height -= te.getHeight();
36761 var te = this.footer.getEl();
36762 te.setWidth(width);
36763 height -= te.getHeight();
36767 if(this.adjustments){
36768 width += this.adjustments[0];
36769 height += this.adjustments[1];
36771 return {"width": width, "height": height};
36774 setSize : function(width, height){
36775 if(this.fitToFrame && !this.ignoreResize(width, height)){
36776 if(this.fitContainer && this.resizeEl != this.el){
36777 this.el.setSize(width, height);
36779 var size = this.adjustForComponents(width, height);
36780 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36781 this.fireEvent('resize', this, size.width, size.height);
36786 * Returns this panel's title
36789 getTitle : function(){
36791 if (typeof(this.title) != 'object') {
36796 for (var k in this.title) {
36797 if (!this.title.hasOwnProperty(k)) {
36801 if (k.indexOf('-') >= 0) {
36802 var s = k.split('-');
36803 for (var i = 0; i<s.length; i++) {
36804 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36807 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36814 * Set this panel's title
36815 * @param {String} title
36817 setTitle : function(title){
36818 this.title = title;
36820 this.region.updatePanelTitle(this, title);
36825 * Returns true is this panel was configured to be closable
36826 * @return {Boolean}
36828 isClosable : function(){
36829 return this.closable;
36832 beforeSlide : function(){
36834 this.resizeEl.clip();
36837 afterSlide : function(){
36839 this.resizeEl.unclip();
36843 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36844 * Will fail silently if the {@link #setUrl} method has not been called.
36845 * This does not activate the panel, just updates its content.
36847 refresh : function(){
36848 if(this.refreshDelegate){
36849 this.loaded = false;
36850 this.refreshDelegate();
36855 * Destroys this panel
36857 destroy : function(){
36858 this.el.removeAllListeners();
36859 var tempEl = document.createElement("span");
36860 tempEl.appendChild(this.el.dom);
36861 tempEl.innerHTML = "";
36867 * form - if the content panel contains a form - this is a reference to it.
36868 * @type {Roo.form.Form}
36872 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36873 * This contains a reference to it.
36879 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36889 * @param {Object} cfg Xtype definition of item to add.
36893 getChildContainer: function () {
36894 return this.getEl();
36899 var ret = new Roo.factory(cfg);
36904 if (cfg.xtype.match(/^Form$/)) {
36907 //if (this.footer) {
36908 // el = this.footer.container.insertSibling(false, 'before');
36910 el = this.el.createChild();
36913 this.form = new Roo.form.Form(cfg);
36916 if ( this.form.allItems.length) {
36917 this.form.render(el.dom);
36921 // should only have one of theses..
36922 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36923 // views.. should not be just added - used named prop 'view''
36925 cfg.el = this.el.appendChild(document.createElement("div"));
36928 var ret = new Roo.factory(cfg);
36930 ret.render && ret.render(false, ''); // render blank..
36940 * @class Roo.bootstrap.panel.Grid
36941 * @extends Roo.bootstrap.panel.Content
36943 * Create a new GridPanel.
36944 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36945 * @param {Object} config A the config object
36951 Roo.bootstrap.panel.Grid = function(config)
36955 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36956 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36958 config.el = this.wrapper;
36959 //this.el = this.wrapper;
36961 if (config.container) {
36962 // ctor'ed from a Border/panel.grid
36965 this.wrapper.setStyle("overflow", "hidden");
36966 this.wrapper.addClass('roo-grid-container');
36971 if(config.toolbar){
36972 var tool_el = this.wrapper.createChild();
36973 this.toolbar = Roo.factory(config.toolbar);
36975 if (config.toolbar.items) {
36976 ti = config.toolbar.items ;
36977 delete config.toolbar.items ;
36981 this.toolbar.render(tool_el);
36982 for(var i =0;i < ti.length;i++) {
36983 // Roo.log(['add child', items[i]]);
36984 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36986 this.toolbar.items = nitems;
36988 delete config.toolbar;
36991 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36992 config.grid.scrollBody = true;;
36993 config.grid.monitorWindowResize = false; // turn off autosizing
36994 config.grid.autoHeight = false;
36995 config.grid.autoWidth = false;
36997 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36999 if (config.background) {
37000 // render grid on panel activation (if panel background)
37001 this.on('activate', function(gp) {
37002 if (!gp.grid.rendered) {
37003 gp.grid.render(this.wrapper);
37004 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37009 this.grid.render(this.wrapper);
37010 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37013 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37014 // ??? needed ??? config.el = this.wrapper;
37019 // xtype created footer. - not sure if will work as we normally have to render first..
37020 if (this.footer && !this.footer.el && this.footer.xtype) {
37022 var ctr = this.grid.getView().getFooterPanel(true);
37023 this.footer.dataSource = this.grid.dataSource;
37024 this.footer = Roo.factory(this.footer, Roo);
37025 this.footer.render(ctr);
37035 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37036 getId : function(){
37037 return this.grid.id;
37041 * Returns the grid for this panel
37042 * @return {Roo.bootstrap.Table}
37044 getGrid : function(){
37048 setSize : function(width, height){
37049 if(!this.ignoreResize(width, height)){
37050 var grid = this.grid;
37051 var size = this.adjustForComponents(width, height);
37052 var gridel = grid.getGridEl();
37053 gridel.setSize(size.width, size.height);
37055 var thd = grid.getGridEl().select('thead',true).first();
37056 var tbd = grid.getGridEl().select('tbody', true).first();
37058 tbd.setSize(width, height - thd.getHeight());
37067 beforeSlide : function(){
37068 this.grid.getView().scroller.clip();
37071 afterSlide : function(){
37072 this.grid.getView().scroller.unclip();
37075 destroy : function(){
37076 this.grid.destroy();
37078 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37083 * @class Roo.bootstrap.panel.Nest
37084 * @extends Roo.bootstrap.panel.Content
37086 * Create a new Panel, that can contain a layout.Border.
37089 * @param {Roo.BorderLayout} layout The layout for this panel
37090 * @param {String/Object} config A string to set only the title or a config object
37092 Roo.bootstrap.panel.Nest = function(config)
37094 // construct with only one argument..
37095 /* FIXME - implement nicer consturctors
37096 if (layout.layout) {
37098 layout = config.layout;
37099 delete config.layout;
37101 if (layout.xtype && !layout.getEl) {
37102 // then layout needs constructing..
37103 layout = Roo.factory(layout, Roo);
37107 config.el = config.layout.getEl();
37109 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37111 config.layout.monitorWindowResize = false; // turn off autosizing
37112 this.layout = config.layout;
37113 this.layout.getEl().addClass("roo-layout-nested-layout");
37120 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37122 setSize : function(width, height){
37123 if(!this.ignoreResize(width, height)){
37124 var size = this.adjustForComponents(width, height);
37125 var el = this.layout.getEl();
37126 if (size.height < 1) {
37127 el.setWidth(size.width);
37129 el.setSize(size.width, size.height);
37131 var touch = el.dom.offsetWidth;
37132 this.layout.layout();
37133 // ie requires a double layout on the first pass
37134 if(Roo.isIE && !this.initialized){
37135 this.initialized = true;
37136 this.layout.layout();
37141 // activate all subpanels if not currently active..
37143 setActiveState : function(active){
37144 this.active = active;
37145 this.setActiveClass(active);
37148 this.fireEvent("deactivate", this);
37152 this.fireEvent("activate", this);
37153 // not sure if this should happen before or after..
37154 if (!this.layout) {
37155 return; // should not happen..
37158 for (var r in this.layout.regions) {
37159 reg = this.layout.getRegion(r);
37160 if (reg.getActivePanel()) {
37161 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37162 reg.setActivePanel(reg.getActivePanel());
37165 if (!reg.panels.length) {
37168 reg.showPanel(reg.getPanel(0));
37177 * Returns the nested BorderLayout for this panel
37178 * @return {Roo.BorderLayout}
37180 getLayout : function(){
37181 return this.layout;
37185 * Adds a xtype elements to the layout of the nested panel
37189 xtype : 'ContentPanel',
37196 xtype : 'NestedLayoutPanel',
37202 items : [ ... list of content panels or nested layout panels.. ]
37206 * @param {Object} cfg Xtype definition of item to add.
37208 addxtype : function(cfg) {
37209 return this.layout.addxtype(cfg);
37214 * Ext JS Library 1.1.1
37215 * Copyright(c) 2006-2007, Ext JS, LLC.
37217 * Originally Released Under LGPL - original licence link has changed is not relivant.
37220 * <script type="text/javascript">
37223 * @class Roo.TabPanel
37224 * @extends Roo.util.Observable
37225 * A lightweight tab container.
37229 // basic tabs 1, built from existing content
37230 var tabs = new Roo.TabPanel("tabs1");
37231 tabs.addTab("script", "View Script");
37232 tabs.addTab("markup", "View Markup");
37233 tabs.activate("script");
37235 // more advanced tabs, built from javascript
37236 var jtabs = new Roo.TabPanel("jtabs");
37237 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37239 // set up the UpdateManager
37240 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37241 var updater = tab2.getUpdateManager();
37242 updater.setDefaultUrl("ajax1.htm");
37243 tab2.on('activate', updater.refresh, updater, true);
37245 // Use setUrl for Ajax loading
37246 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37247 tab3.setUrl("ajax2.htm", null, true);
37250 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37253 jtabs.activate("jtabs-1");
37256 * Create a new TabPanel.
37257 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37258 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37260 Roo.bootstrap.panel.Tabs = function(config){
37262 * The container element for this TabPanel.
37263 * @type Roo.Element
37265 this.el = Roo.get(config.el);
37268 if(typeof config == "boolean"){
37269 this.tabPosition = config ? "bottom" : "top";
37271 Roo.apply(this, config);
37275 if(this.tabPosition == "bottom"){
37276 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37277 this.el.addClass("roo-tabs-bottom");
37279 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37280 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37281 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37283 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37285 if(this.tabPosition != "bottom"){
37286 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37287 * @type Roo.Element
37289 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37290 this.el.addClass("roo-tabs-top");
37294 this.bodyEl.setStyle("position", "relative");
37296 this.active = null;
37297 this.activateDelegate = this.activate.createDelegate(this);
37302 * Fires when the active tab changes
37303 * @param {Roo.TabPanel} this
37304 * @param {Roo.TabPanelItem} activePanel The new active tab
37308 * @event beforetabchange
37309 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37310 * @param {Roo.TabPanel} this
37311 * @param {Object} e Set cancel to true on this object to cancel the tab change
37312 * @param {Roo.TabPanelItem} tab The tab being changed to
37314 "beforetabchange" : true
37317 Roo.EventManager.onWindowResize(this.onResize, this);
37318 this.cpad = this.el.getPadding("lr");
37319 this.hiddenCount = 0;
37322 // toolbar on the tabbar support...
37323 if (this.toolbar) {
37324 alert("no toolbar support yet");
37325 this.toolbar = false;
37327 var tcfg = this.toolbar;
37328 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37329 this.toolbar = new Roo.Toolbar(tcfg);
37330 if (Roo.isSafari) {
37331 var tbl = tcfg.container.child('table', true);
37332 tbl.setAttribute('width', '100%');
37340 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37343 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37345 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37347 tabPosition : "top",
37349 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37351 currentTabWidth : 0,
37353 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37357 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37361 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37363 preferredTabWidth : 175,
37365 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37367 resizeTabs : false,
37369 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37371 monitorResize : true,
37373 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37378 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37379 * @param {String} id The id of the div to use <b>or create</b>
37380 * @param {String} text The text for the tab
37381 * @param {String} content (optional) Content to put in the TabPanelItem body
37382 * @param {Boolean} closable (optional) True to create a close icon on the tab
37383 * @return {Roo.TabPanelItem} The created TabPanelItem
37385 addTab : function(id, text, content, closable, tpl)
37387 var item = new Roo.bootstrap.panel.TabItem({
37391 closable : closable,
37394 this.addTabItem(item);
37396 item.setContent(content);
37402 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37403 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37404 * @return {Roo.TabPanelItem}
37406 getTab : function(id){
37407 return this.items[id];
37411 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37412 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37414 hideTab : function(id){
37415 var t = this.items[id];
37418 this.hiddenCount++;
37419 this.autoSizeTabs();
37424 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37425 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37427 unhideTab : function(id){
37428 var t = this.items[id];
37430 t.setHidden(false);
37431 this.hiddenCount--;
37432 this.autoSizeTabs();
37437 * Adds an existing {@link Roo.TabPanelItem}.
37438 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37440 addTabItem : function(item){
37441 this.items[item.id] = item;
37442 this.items.push(item);
37443 // if(this.resizeTabs){
37444 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37445 // this.autoSizeTabs();
37447 // item.autoSize();
37452 * Removes a {@link Roo.TabPanelItem}.
37453 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37455 removeTab : function(id){
37456 var items = this.items;
37457 var tab = items[id];
37458 if(!tab) { return; }
37459 var index = items.indexOf(tab);
37460 if(this.active == tab && items.length > 1){
37461 var newTab = this.getNextAvailable(index);
37466 this.stripEl.dom.removeChild(tab.pnode.dom);
37467 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37468 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37470 items.splice(index, 1);
37471 delete this.items[tab.id];
37472 tab.fireEvent("close", tab);
37473 tab.purgeListeners();
37474 this.autoSizeTabs();
37477 getNextAvailable : function(start){
37478 var items = this.items;
37480 // look for a next tab that will slide over to
37481 // replace the one being removed
37482 while(index < items.length){
37483 var item = items[++index];
37484 if(item && !item.isHidden()){
37488 // if one isn't found select the previous tab (on the left)
37491 var item = items[--index];
37492 if(item && !item.isHidden()){
37500 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37501 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37503 disableTab : function(id){
37504 var tab = this.items[id];
37505 if(tab && this.active != tab){
37511 * Enables a {@link Roo.TabPanelItem} that is disabled.
37512 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37514 enableTab : function(id){
37515 var tab = this.items[id];
37520 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37521 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37522 * @return {Roo.TabPanelItem} The TabPanelItem.
37524 activate : function(id){
37525 var tab = this.items[id];
37529 if(tab == this.active || tab.disabled){
37533 this.fireEvent("beforetabchange", this, e, tab);
37534 if(e.cancel !== true && !tab.disabled){
37536 this.active.hide();
37538 this.active = this.items[id];
37539 this.active.show();
37540 this.fireEvent("tabchange", this, this.active);
37546 * Gets the active {@link Roo.TabPanelItem}.
37547 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37549 getActiveTab : function(){
37550 return this.active;
37554 * Updates the tab body element to fit the height of the container element
37555 * for overflow scrolling
37556 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37558 syncHeight : function(targetHeight){
37559 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37560 var bm = this.bodyEl.getMargins();
37561 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37562 this.bodyEl.setHeight(newHeight);
37566 onResize : function(){
37567 if(this.monitorResize){
37568 this.autoSizeTabs();
37573 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37575 beginUpdate : function(){
37576 this.updating = true;
37580 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37582 endUpdate : function(){
37583 this.updating = false;
37584 this.autoSizeTabs();
37588 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37590 autoSizeTabs : function(){
37591 var count = this.items.length;
37592 var vcount = count - this.hiddenCount;
37593 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37596 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37597 var availWidth = Math.floor(w / vcount);
37598 var b = this.stripBody;
37599 if(b.getWidth() > w){
37600 var tabs = this.items;
37601 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37602 if(availWidth < this.minTabWidth){
37603 /*if(!this.sleft){ // incomplete scrolling code
37604 this.createScrollButtons();
37607 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37610 if(this.currentTabWidth < this.preferredTabWidth){
37611 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37617 * Returns the number of tabs in this TabPanel.
37620 getCount : function(){
37621 return this.items.length;
37625 * Resizes all the tabs to the passed width
37626 * @param {Number} The new width
37628 setTabWidth : function(width){
37629 this.currentTabWidth = width;
37630 for(var i = 0, len = this.items.length; i < len; i++) {
37631 if(!this.items[i].isHidden()) {
37632 this.items[i].setWidth(width);
37638 * Destroys this TabPanel
37639 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37641 destroy : function(removeEl){
37642 Roo.EventManager.removeResizeListener(this.onResize, this);
37643 for(var i = 0, len = this.items.length; i < len; i++){
37644 this.items[i].purgeListeners();
37646 if(removeEl === true){
37647 this.el.update("");
37652 createStrip : function(container)
37654 var strip = document.createElement("nav");
37655 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37656 container.appendChild(strip);
37660 createStripList : function(strip)
37662 // div wrapper for retard IE
37663 // returns the "tr" element.
37664 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37665 //'<div class="x-tabs-strip-wrap">'+
37666 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37667 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37668 return strip.firstChild; //.firstChild.firstChild.firstChild;
37670 createBody : function(container)
37672 var body = document.createElement("div");
37673 Roo.id(body, "tab-body");
37674 //Roo.fly(body).addClass("x-tabs-body");
37675 Roo.fly(body).addClass("tab-content");
37676 container.appendChild(body);
37679 createItemBody :function(bodyEl, id){
37680 var body = Roo.getDom(id);
37682 body = document.createElement("div");
37685 //Roo.fly(body).addClass("x-tabs-item-body");
37686 Roo.fly(body).addClass("tab-pane");
37687 bodyEl.insertBefore(body, bodyEl.firstChild);
37691 createStripElements : function(stripEl, text, closable, tpl)
37693 var td = document.createElement("li"); // was td..
37696 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37699 stripEl.appendChild(td);
37701 td.className = "x-tabs-closable";
37702 if(!this.closeTpl){
37703 this.closeTpl = new Roo.Template(
37704 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37705 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37706 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37709 var el = this.closeTpl.overwrite(td, {"text": text});
37710 var close = el.getElementsByTagName("div")[0];
37711 var inner = el.getElementsByTagName("em")[0];
37712 return {"el": el, "close": close, "inner": inner};
37715 // not sure what this is..
37716 // if(!this.tabTpl){
37717 //this.tabTpl = new Roo.Template(
37718 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37719 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37721 // this.tabTpl = new Roo.Template(
37722 // '<a href="#">' +
37723 // '<span unselectable="on"' +
37724 // (this.disableTooltips ? '' : ' title="{text}"') +
37725 // ' >{text}</span></a>'
37731 var template = tpl || this.tabTpl || false;
37735 template = new Roo.Template(
37737 '<span unselectable="on"' +
37738 (this.disableTooltips ? '' : ' title="{text}"') +
37739 ' >{text}</span></a>'
37743 switch (typeof(template)) {
37747 template = new Roo.Template(template);
37753 var el = template.overwrite(td, {"text": text});
37755 var inner = el.getElementsByTagName("span")[0];
37757 return {"el": el, "inner": inner};
37765 * @class Roo.TabPanelItem
37766 * @extends Roo.util.Observable
37767 * Represents an individual item (tab plus body) in a TabPanel.
37768 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37769 * @param {String} id The id of this TabPanelItem
37770 * @param {String} text The text for the tab of this TabPanelItem
37771 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37773 Roo.bootstrap.panel.TabItem = function(config){
37775 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37776 * @type Roo.TabPanel
37778 this.tabPanel = config.panel;
37780 * The id for this TabPanelItem
37783 this.id = config.id;
37785 this.disabled = false;
37787 this.text = config.text;
37789 this.loaded = false;
37790 this.closable = config.closable;
37793 * The body element for this TabPanelItem.
37794 * @type Roo.Element
37796 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37797 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37798 this.bodyEl.setStyle("display", "block");
37799 this.bodyEl.setStyle("zoom", "1");
37800 //this.hideAction();
37802 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37804 this.el = Roo.get(els.el);
37805 this.inner = Roo.get(els.inner, true);
37806 this.textEl = Roo.get(this.el.dom.firstChild, true);
37807 this.pnode = Roo.get(els.el.parentNode, true);
37808 // this.el.on("mousedown", this.onTabMouseDown, this);
37809 this.el.on("click", this.onTabClick, this);
37811 if(config.closable){
37812 var c = Roo.get(els.close, true);
37813 c.dom.title = this.closeText;
37814 c.addClassOnOver("close-over");
37815 c.on("click", this.closeClick, this);
37821 * Fires when this tab becomes the active tab.
37822 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37823 * @param {Roo.TabPanelItem} this
37827 * @event beforeclose
37828 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37829 * @param {Roo.TabPanelItem} this
37830 * @param {Object} e Set cancel to true on this object to cancel the close.
37832 "beforeclose": true,
37835 * Fires when this tab is closed.
37836 * @param {Roo.TabPanelItem} this
37840 * @event deactivate
37841 * Fires when this tab is no longer the active tab.
37842 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37843 * @param {Roo.TabPanelItem} this
37845 "deactivate" : true
37847 this.hidden = false;
37849 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37852 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37854 purgeListeners : function(){
37855 Roo.util.Observable.prototype.purgeListeners.call(this);
37856 this.el.removeAllListeners();
37859 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37862 this.pnode.addClass("active");
37865 this.tabPanel.stripWrap.repaint();
37867 this.fireEvent("activate", this.tabPanel, this);
37871 * Returns true if this tab is the active tab.
37872 * @return {Boolean}
37874 isActive : function(){
37875 return this.tabPanel.getActiveTab() == this;
37879 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37882 this.pnode.removeClass("active");
37884 this.fireEvent("deactivate", this.tabPanel, this);
37887 hideAction : function(){
37888 this.bodyEl.hide();
37889 this.bodyEl.setStyle("position", "absolute");
37890 this.bodyEl.setLeft("-20000px");
37891 this.bodyEl.setTop("-20000px");
37894 showAction : function(){
37895 this.bodyEl.setStyle("position", "relative");
37896 this.bodyEl.setTop("");
37897 this.bodyEl.setLeft("");
37898 this.bodyEl.show();
37902 * Set the tooltip for the tab.
37903 * @param {String} tooltip The tab's tooltip
37905 setTooltip : function(text){
37906 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37907 this.textEl.dom.qtip = text;
37908 this.textEl.dom.removeAttribute('title');
37910 this.textEl.dom.title = text;
37914 onTabClick : function(e){
37915 e.preventDefault();
37916 this.tabPanel.activate(this.id);
37919 onTabMouseDown : function(e){
37920 e.preventDefault();
37921 this.tabPanel.activate(this.id);
37924 getWidth : function(){
37925 return this.inner.getWidth();
37928 setWidth : function(width){
37929 var iwidth = width - this.pnode.getPadding("lr");
37930 this.inner.setWidth(iwidth);
37931 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37932 this.pnode.setWidth(width);
37936 * Show or hide the tab
37937 * @param {Boolean} hidden True to hide or false to show.
37939 setHidden : function(hidden){
37940 this.hidden = hidden;
37941 this.pnode.setStyle("display", hidden ? "none" : "");
37945 * Returns true if this tab is "hidden"
37946 * @return {Boolean}
37948 isHidden : function(){
37949 return this.hidden;
37953 * Returns the text for this tab
37956 getText : function(){
37960 autoSize : function(){
37961 //this.el.beginMeasure();
37962 this.textEl.setWidth(1);
37964 * #2804 [new] Tabs in Roojs
37965 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37967 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37968 //this.el.endMeasure();
37972 * Sets the text for the tab (Note: this also sets the tooltip text)
37973 * @param {String} text The tab's text and tooltip
37975 setText : function(text){
37977 this.textEl.update(text);
37978 this.setTooltip(text);
37979 //if(!this.tabPanel.resizeTabs){
37980 // this.autoSize();
37984 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37986 activate : function(){
37987 this.tabPanel.activate(this.id);
37991 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37993 disable : function(){
37994 if(this.tabPanel.active != this){
37995 this.disabled = true;
37996 this.pnode.addClass("disabled");
38001 * Enables this TabPanelItem if it was previously disabled.
38003 enable : function(){
38004 this.disabled = false;
38005 this.pnode.removeClass("disabled");
38009 * Sets the content for this TabPanelItem.
38010 * @param {String} content The content
38011 * @param {Boolean} loadScripts true to look for and load scripts
38013 setContent : function(content, loadScripts){
38014 this.bodyEl.update(content, loadScripts);
38018 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38019 * @return {Roo.UpdateManager} The UpdateManager
38021 getUpdateManager : function(){
38022 return this.bodyEl.getUpdateManager();
38026 * Set a URL to be used to load the content for this TabPanelItem.
38027 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38028 * @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)
38029 * @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)
38030 * @return {Roo.UpdateManager} The UpdateManager
38032 setUrl : function(url, params, loadOnce){
38033 if(this.refreshDelegate){
38034 this.un('activate', this.refreshDelegate);
38036 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38037 this.on("activate", this.refreshDelegate);
38038 return this.bodyEl.getUpdateManager();
38042 _handleRefresh : function(url, params, loadOnce){
38043 if(!loadOnce || !this.loaded){
38044 var updater = this.bodyEl.getUpdateManager();
38045 updater.update(url, params, this._setLoaded.createDelegate(this));
38050 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38051 * Will fail silently if the setUrl method has not been called.
38052 * This does not activate the panel, just updates its content.
38054 refresh : function(){
38055 if(this.refreshDelegate){
38056 this.loaded = false;
38057 this.refreshDelegate();
38062 _setLoaded : function(){
38063 this.loaded = true;
38067 closeClick : function(e){
38070 this.fireEvent("beforeclose", this, o);
38071 if(o.cancel !== true){
38072 this.tabPanel.removeTab(this.id);
38076 * The text displayed in the tooltip for the close icon.
38079 closeText : "Close this tab"
38082 * This script refer to:
38083 * Title: International Telephone Input
38084 * Author: Jack O'Connor
38085 * Code version: v12.1.12
38086 * Availability: https://github.com/jackocnr/intl-tel-input.git
38089 Roo.bootstrap.PhoneInputData = function() {
38092 "Afghanistan (افغانستان)",
38097 "Albania (Shqipëri)",
38102 "Algeria (الجزائر)",
38127 "Antigua and Barbuda",
38137 "Armenia (Հայաստան)",
38153 "Austria (Österreich)",
38158 "Azerbaijan (Azərbaycan)",
38168 "Bahrain (البحرين)",
38173 "Bangladesh (বাংলাদেশ)",
38183 "Belarus (Беларусь)",
38188 "Belgium (België)",
38218 "Bosnia and Herzegovina (Босна и Херцеговина)",
38233 "British Indian Ocean Territory",
38238 "British Virgin Islands",
38248 "Bulgaria (България)",
38258 "Burundi (Uburundi)",
38263 "Cambodia (កម្ពុជា)",
38268 "Cameroon (Cameroun)",
38277 ["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"]
38280 "Cape Verde (Kabu Verdi)",
38285 "Caribbean Netherlands",
38296 "Central African Republic (République centrafricaine)",
38316 "Christmas Island",
38322 "Cocos (Keeling) Islands",
38333 "Comoros (جزر القمر)",
38338 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38343 "Congo (Republic) (Congo-Brazzaville)",
38363 "Croatia (Hrvatska)",
38384 "Czech Republic (Česká republika)",
38389 "Denmark (Danmark)",
38404 "Dominican Republic (República Dominicana)",
38408 ["809", "829", "849"]
38426 "Equatorial Guinea (Guinea Ecuatorial)",
38446 "Falkland Islands (Islas Malvinas)",
38451 "Faroe Islands (Føroyar)",
38472 "French Guiana (Guyane française)",
38477 "French Polynesia (Polynésie française)",
38492 "Georgia (საქართველო)",
38497 "Germany (Deutschland)",
38517 "Greenland (Kalaallit Nunaat)",
38554 "Guinea-Bissau (Guiné Bissau)",
38579 "Hungary (Magyarország)",
38584 "Iceland (Ísland)",
38604 "Iraq (العراق)",
38620 "Israel (ישראל)",
38647 "Jordan (الأردن)",
38652 "Kazakhstan (Казахстан)",
38673 "Kuwait (الكويت)",
38678 "Kyrgyzstan (Кыргызстан)",
38688 "Latvia (Latvija)",
38693 "Lebanon (لبنان)",
38708 "Libya (ليبيا)",
38718 "Lithuania (Lietuva)",
38733 "Macedonia (FYROM) (Македонија)",
38738 "Madagascar (Madagasikara)",
38768 "Marshall Islands",
38778 "Mauritania (موريتانيا)",
38783 "Mauritius (Moris)",
38804 "Moldova (Republica Moldova)",
38814 "Mongolia (Монгол)",
38819 "Montenegro (Crna Gora)",
38829 "Morocco (المغرب)",
38835 "Mozambique (Moçambique)",
38840 "Myanmar (Burma) (မြန်မာ)",
38845 "Namibia (Namibië)",
38860 "Netherlands (Nederland)",
38865 "New Caledonia (Nouvelle-Calédonie)",
38900 "North Korea (조선 민주주의 인민 공화국)",
38905 "Northern Mariana Islands",
38921 "Pakistan (پاکستان)",
38931 "Palestine (فلسطين)",
38941 "Papua New Guinea",
38983 "Réunion (La Réunion)",
38989 "Romania (România)",
39005 "Saint Barthélemy",
39016 "Saint Kitts and Nevis",
39026 "Saint Martin (Saint-Martin (partie française))",
39032 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39037 "Saint Vincent and the Grenadines",
39052 "São Tomé and Príncipe (São Tomé e Príncipe)",
39057 "Saudi Arabia (المملكة العربية السعودية)",
39062 "Senegal (Sénégal)",
39092 "Slovakia (Slovensko)",
39097 "Slovenia (Slovenija)",
39107 "Somalia (Soomaaliya)",
39117 "South Korea (대한민국)",
39122 "South Sudan (جنوب السودان)",
39132 "Sri Lanka (ශ්රී ලංකාව)",
39137 "Sudan (السودان)",
39147 "Svalbard and Jan Mayen",
39158 "Sweden (Sverige)",
39163 "Switzerland (Schweiz)",
39168 "Syria (سوريا)",
39213 "Trinidad and Tobago",
39218 "Tunisia (تونس)",
39223 "Turkey (Türkiye)",
39233 "Turks and Caicos Islands",
39243 "U.S. Virgin Islands",
39253 "Ukraine (Україна)",
39258 "United Arab Emirates (الإمارات العربية المتحدة)",
39280 "Uzbekistan (Oʻzbekiston)",
39290 "Vatican City (Città del Vaticano)",
39301 "Vietnam (Việt Nam)",
39306 "Wallis and Futuna (Wallis-et-Futuna)",
39311 "Western Sahara (الصحراء الغربية)",
39317 "Yemen (اليمن)",
39341 * This script refer to:
39342 * Title: International Telephone Input
39343 * Author: Jack O'Connor
39344 * Code version: v12.1.12
39345 * Availability: https://github.com/jackocnr/intl-tel-input.git
39349 * @class Roo.bootstrap.PhoneInput
39350 * @extends Roo.bootstrap.TriggerField
39351 * An input with International dial-code selection
39353 * @cfg {String} defaultDialCode default '+852'
39354 * @cfg {Array} preferedCountries default []
39357 * Create a new PhoneInput.
39358 * @param {Object} config Configuration options
39361 Roo.bootstrap.PhoneInput = function(config) {
39362 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39365 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39367 listWidth: undefined,
39369 selectedClass: 'active',
39371 invalidClass : "has-warning",
39373 validClass: 'has-success',
39375 allowed: '0123456789',
39378 * @cfg {String} defaultDialCode The default dial code when initializing the input
39380 defaultDialCode: '+852',
39383 * @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
39385 preferedCountries: false,
39387 getAutoCreate : function()
39389 var data = Roo.bootstrap.PhoneInputData();
39390 var align = this.labelAlign || this.parentLabelAlign();
39393 this.allCountries = [];
39394 this.dialCodeMapping = [];
39396 for (var i = 0; i < data.length; i++) {
39398 this.allCountries[i] = {
39402 priority: c[3] || 0,
39403 areaCodes: c[4] || null
39405 this.dialCodeMapping[c[2]] = {
39408 priority: c[3] || 0,
39409 areaCodes: c[4] || null
39421 cls : 'form-control tel-input',
39422 autocomplete: 'new-password'
39425 var hiddenInput = {
39428 cls: 'hidden-tel-input'
39432 hiddenInput.name = this.name;
39435 if (this.disabled) {
39436 input.disabled = true;
39439 var flag_container = {
39456 cls: this.hasFeedback ? 'has-feedback' : '',
39462 cls: 'dial-code-holder',
39469 cls: 'roo-select2-container input-group',
39476 if (this.fieldLabel.length) {
39479 tooltip: 'This field is required'
39485 cls: 'control-label',
39491 html: this.fieldLabel
39494 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39500 if(this.indicatorpos == 'right') {
39501 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39508 if(align == 'left') {
39516 if(this.labelWidth > 12){
39517 label.style = "width: " + this.labelWidth + 'px';
39519 if(this.labelWidth < 13 && this.labelmd == 0){
39520 this.labelmd = this.labelWidth;
39522 if(this.labellg > 0){
39523 label.cls += ' col-lg-' + this.labellg;
39524 input.cls += ' col-lg-' + (12 - this.labellg);
39526 if(this.labelmd > 0){
39527 label.cls += ' col-md-' + this.labelmd;
39528 container.cls += ' col-md-' + (12 - this.labelmd);
39530 if(this.labelsm > 0){
39531 label.cls += ' col-sm-' + this.labelsm;
39532 container.cls += ' col-sm-' + (12 - this.labelsm);
39534 if(this.labelxs > 0){
39535 label.cls += ' col-xs-' + this.labelxs;
39536 container.cls += ' col-xs-' + (12 - this.labelxs);
39546 var settings = this;
39548 ['xs','sm','md','lg'].map(function(size){
39549 if (settings[size]) {
39550 cfg.cls += ' col-' + size + '-' + settings[size];
39554 this.store = new Roo.data.Store({
39555 proxy : new Roo.data.MemoryProxy({}),
39556 reader : new Roo.data.JsonReader({
39567 'name' : 'dialCode',
39571 'name' : 'priority',
39575 'name' : 'areaCodes',
39582 if(!this.preferedCountries) {
39583 this.preferedCountries = [
39590 var p = this.preferedCountries.reverse();
39593 for (var i = 0; i < p.length; i++) {
39594 for (var j = 0; j < this.allCountries.length; j++) {
39595 if(this.allCountries[j].iso2 == p[i]) {
39596 var t = this.allCountries[j];
39597 this.allCountries.splice(j,1);
39598 this.allCountries.unshift(t);
39604 this.store.proxy.data = {
39606 data: this.allCountries
39612 initEvents : function()
39615 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39617 this.indicator = this.indicatorEl();
39618 this.flag = this.flagEl();
39619 this.dialCodeHolder = this.dialCodeHolderEl();
39621 this.trigger = this.el.select('div.flag-box',true).first();
39622 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39627 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39628 _this.list.setWidth(lw);
39631 this.list.on('mouseover', this.onViewOver, this);
39632 this.list.on('mousemove', this.onViewMove, this);
39633 this.inputEl().on("keyup", this.onKeyUp, this);
39635 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39637 this.view = new Roo.View(this.list, this.tpl, {
39638 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39641 this.view.on('click', this.onViewClick, this);
39642 this.setValue(this.defaultDialCode);
39645 onTriggerClick : function(e)
39647 Roo.log('trigger click');
39652 if(this.isExpanded()){
39654 this.hasFocus = false;
39656 this.store.load({});
39657 this.hasFocus = true;
39662 isExpanded : function()
39664 return this.list.isVisible();
39667 collapse : function()
39669 if(!this.isExpanded()){
39673 Roo.get(document).un('mousedown', this.collapseIf, this);
39674 Roo.get(document).un('mousewheel', this.collapseIf, this);
39675 this.fireEvent('collapse', this);
39679 expand : function()
39683 if(this.isExpanded() || !this.hasFocus){
39687 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39688 this.list.setWidth(lw);
39691 this.restrictHeight();
39693 Roo.get(document).on('mousedown', this.collapseIf, this);
39694 Roo.get(document).on('mousewheel', this.collapseIf, this);
39696 this.fireEvent('expand', this);
39699 restrictHeight : function()
39701 this.list.alignTo(this.inputEl(), this.listAlign);
39702 this.list.alignTo(this.inputEl(), this.listAlign);
39705 onViewOver : function(e, t)
39707 if(this.inKeyMode){
39710 var item = this.view.findItemFromChild(t);
39713 var index = this.view.indexOf(item);
39714 this.select(index, false);
39719 onViewClick : function(view, doFocus, el, e)
39721 var index = this.view.getSelectedIndexes()[0];
39723 var r = this.store.getAt(index);
39726 this.onSelect(r, index);
39728 if(doFocus !== false && !this.blockFocus){
39729 this.inputEl().focus();
39733 onViewMove : function(e, t)
39735 this.inKeyMode = false;
39738 select : function(index, scrollIntoView)
39740 this.selectedIndex = index;
39741 this.view.select(index);
39742 if(scrollIntoView !== false){
39743 var el = this.view.getNode(index);
39745 this.list.scrollChildIntoView(el, false);
39750 createList : function()
39752 this.list = Roo.get(document.body).createChild({
39754 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39755 style: 'display:none'
39757 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39760 collapseIf : function(e)
39762 var in_combo = e.within(this.el);
39763 var in_list = e.within(this.list);
39764 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39766 if (in_combo || in_list || is_list) {
39772 onSelect : function(record, index)
39774 if(this.fireEvent('beforeselect', this, record, index) !== false){
39776 this.setFlagClass(record.data.iso2);
39777 this.setDialCode(record.data.dialCode);
39778 this.hasFocus = false;
39780 this.fireEvent('select', this, record, index);
39784 flagEl : function()
39786 var flag = this.el.select('div.flag',true).first();
39793 dialCodeHolderEl : function()
39795 var d = this.el.select('input.dial-code-holder',true).first();
39802 setDialCode : function(v)
39804 this.dialCodeHolder.dom.value = '+'+v;
39807 setFlagClass : function(n)
39809 this.flag.dom.className = 'flag '+n;
39812 getValue : function()
39814 var v = this.inputEl().getValue();
39815 if(this.dialCodeHolder) {
39816 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39821 setValue : function(v)
39823 var d = this.getDialCode(v);
39825 //invalid dial code
39826 if(v.length == 0 || !d || d.length == 0) {
39828 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39829 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39835 this.setFlagClass(this.dialCodeMapping[d].iso2);
39836 this.setDialCode(d);
39837 this.inputEl().dom.value = v.replace('+'+d,'');
39838 this.hiddenEl().dom.value = this.getValue();
39843 getDialCode : function(v = '')
39845 if (v.length == 0) {
39846 return this.dialCodeHolder.dom.value;
39850 if (v.charAt(0) != "+") {
39853 var numericChars = "";
39854 for (var i = 1; i < v.length; i++) {
39855 var c = v.charAt(i);
39858 if (this.dialCodeMapping[numericChars]) {
39859 dialCode = v.substr(1, i);
39861 if (numericChars.length == 4) {
39871 this.setValue(this.defaultDialCode);
39875 hiddenEl : function()
39877 return this.el.select('input.hidden-tel-input',true).first();
39880 onKeyUp : function(e){
39882 var k = e.getKey();
39883 var c = e.getCharCode();
39886 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39887 this.allowed.indexOf(String.fromCharCode(c)) === -1
39892 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39895 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39899 this.setValue(this.getValue());
39904 * @class Roo.bootstrap.MoneyField
39905 * @extends Roo.bootstrap.ComboBox
39906 * Bootstrap MoneyField class
39909 * Create a new MoneyField.
39910 * @param {Object} config Configuration options
39913 Roo.bootstrap.MoneyField = function(config) {
39915 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39919 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39922 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39924 allowDecimals : true,
39926 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39928 decimalSeparator : ".",
39930 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39932 decimalPrecision : 2,
39934 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39936 allowNegative : true,
39938 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39940 minValue : Number.NEGATIVE_INFINITY,
39942 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39944 maxValue : Number.MAX_VALUE,
39946 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39948 minText : "The minimum value for this field is {0}",
39950 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39952 maxText : "The maximum value for this field is {0}",
39954 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39955 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39957 nanText : "{0} is not a valid number",
39959 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39970 getAutoCreate : function()
39972 var align = this.labelAlign || this.parentLabelAlign();
39984 cls : 'form-control roo-money-amount-input',
39985 autocomplete: 'new-password'
39989 input.name = this.name;
39992 if (this.disabled) {
39993 input.disabled = true;
39996 var clg = 12 - this.inputlg;
39997 var cmd = 12 - this.inputmd;
39998 var csm = 12 - this.inputsm;
39999 var cxs = 12 - this.inputxs;
40003 cls : 'row roo-money-field',
40007 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40011 cls: 'roo-select2-container input-group',
40015 cls : 'form-control roo-money-currency-input',
40016 autocomplete: 'new-password',
40018 name : this.currencyName
40022 cls : 'input-group-addon',
40036 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40040 cls: this.hasFeedback ? 'has-feedback' : '',
40051 if (this.fieldLabel.length) {
40054 tooltip: 'This field is required'
40060 cls: 'control-label',
40066 html: this.fieldLabel
40069 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40075 if(this.indicatorpos == 'right') {
40076 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40083 if(align == 'left') {
40091 if(this.labelWidth > 12){
40092 label.style = "width: " + this.labelWidth + 'px';
40094 if(this.labelWidth < 13 && this.labelmd == 0){
40095 this.labelmd = this.labelWidth;
40097 if(this.labellg > 0){
40098 label.cls += ' col-lg-' + this.labellg;
40099 input.cls += ' col-lg-' + (12 - this.labellg);
40101 if(this.labelmd > 0){
40102 label.cls += ' col-md-' + this.labelmd;
40103 container.cls += ' col-md-' + (12 - this.labelmd);
40105 if(this.labelsm > 0){
40106 label.cls += ' col-sm-' + this.labelsm;
40107 container.cls += ' col-sm-' + (12 - this.labelsm);
40109 if(this.labelxs > 0){
40110 label.cls += ' col-xs-' + this.labelxs;
40111 container.cls += ' col-xs-' + (12 - this.labelxs);
40121 var settings = this;
40123 ['xs','sm','md','lg'].map(function(size){
40124 if (settings[size]) {
40125 cfg.cls += ' col-' + size + '-' + settings[size];
40133 initEvents : function()
40135 this.indicator = this.indicatorEl();
40137 this.initCurrencyEvent();
40139 this.initNumberEvent();
40143 initCurrencyEvent : function()
40146 throw "can not find store for combo";
40149 this.store = Roo.factory(this.store, Roo.data);
40150 this.store.parent = this;
40154 this.triggerEl = this.el.select('.input-group-addon', true).first();
40156 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40161 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40162 _this.list.setWidth(lw);
40165 this.list.on('mouseover', this.onViewOver, this);
40166 this.list.on('mousemove', this.onViewMove, this);
40167 this.list.on('scroll', this.onViewScroll, this);
40170 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40173 this.view = new Roo.View(this.list, this.tpl, {
40174 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40177 this.view.on('click', this.onViewClick, this);
40179 this.store.on('beforeload', this.onBeforeLoad, this);
40180 this.store.on('load', this.onLoad, this);
40181 this.store.on('loadexception', this.onLoadException, this);
40183 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40184 "up" : function(e){
40185 this.inKeyMode = true;
40189 "down" : function(e){
40190 if(!this.isExpanded()){
40191 this.onTriggerClick();
40193 this.inKeyMode = true;
40198 "enter" : function(e){
40201 if(this.fireEvent("specialkey", this, e)){
40202 this.onViewClick(false);
40208 "esc" : function(e){
40212 "tab" : function(e){
40215 if(this.fireEvent("specialkey", this, e)){
40216 this.onViewClick(false);
40224 doRelay : function(foo, bar, hname){
40225 if(hname == 'down' || this.scope.isExpanded()){
40226 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40234 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40238 initNumberEvent : function(e)
40240 this.inputEl().on("keydown" , this.fireKey, this);
40241 this.inputEl().on("focus", this.onFocus, this);
40242 this.inputEl().on("blur", this.onBlur, this);
40244 this.inputEl().relayEvent('keyup', this);
40246 if(this.indicator){
40247 this.indicator.addClass('invisible');
40250 this.originalValue = this.getValue();
40252 if(this.validationEvent == 'keyup'){
40253 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40254 this.inputEl().on('keyup', this.filterValidation, this);
40256 else if(this.validationEvent !== false){
40257 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40260 if(this.selectOnFocus){
40261 this.on("focus", this.preFocus, this);
40264 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40265 this.inputEl().on("keypress", this.filterKeys, this);
40267 this.inputEl().relayEvent('keypress', this);
40270 var allowed = "0123456789";
40272 if(this.allowDecimals){
40273 allowed += this.decimalSeparator;
40276 if(this.allowNegative){
40280 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40282 var keyPress = function(e){
40284 var k = e.getKey();
40286 var c = e.getCharCode();
40289 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40290 allowed.indexOf(String.fromCharCode(c)) === -1
40296 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40300 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40305 this.inputEl().on("keypress", keyPress, this);
40309 onTriggerClick : function(e)
40316 this.loadNext = false;
40318 if(this.isExpanded()){
40323 this.hasFocus = true;
40325 if(this.triggerAction == 'all') {
40326 this.doQuery(this.allQuery, true);
40330 this.doQuery(this.getRawValue());
40333 getCurrency : function()
40335 var v = this.currencyEl().getValue();
40340 restrictHeight : function()
40342 this.list.alignTo(this.currencyEl(), this.listAlign);
40343 this.list.alignTo(this.currencyEl(), this.listAlign);
40346 onViewClick : function(view, doFocus, el, e)
40348 var index = this.view.getSelectedIndexes()[0];
40350 var r = this.store.getAt(index);
40353 this.onSelect(r, index);
40357 onSelect : function(record, index){
40359 if(this.fireEvent('beforeselect', this, record, index) !== false){
40361 this.setFromCurrencyData(index > -1 ? record.data : false);
40365 this.fireEvent('select', this, record, index);
40369 setFromCurrencyData : function(o)
40373 this.lastCurrency = o;
40375 if (this.currencyField) {
40376 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40378 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40381 this.lastSelectionText = currency;
40383 this.setCurrency(currency);
40386 setFromData : function(o)
40390 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40392 this.setFromCurrencyData(c);
40397 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40399 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40402 this.setValue(value);
40406 setCurrency : function(v)
40408 this.currencyValue = v;
40411 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40416 setValue : function(v)
40418 v = this.fixPrecision(v);
40420 v = String(v).replace(".", this.decimalSeparator);
40425 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40430 getRawValue : function()
40432 var v = this.inputEl().getValue();
40437 getValue : function()
40439 return this.fixPrecision(this.parseValue(this.getRawValue()));
40442 parseValue : function(value)
40444 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40445 return isNaN(value) ? '' : value;
40448 fixPrecision : function(value)
40450 var nan = isNaN(value);
40452 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40453 return nan ? '' : value;
40456 return parseFloat(value).toFixed(this.decimalPrecision);
40459 decimalPrecisionFcn : function(v)
40461 return Math.floor(v);
40464 validateValue : function(value)
40466 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40470 var num = this.parseValue(value);
40473 this.markInvalid(String.format(this.nanText, value));
40477 if(num < this.minValue){
40478 this.markInvalid(String.format(this.minText, this.minValue));
40482 if(num > this.maxValue){
40483 this.markInvalid(String.format(this.maxText, this.maxValue));
40490 validate : function()
40492 if(this.disabled || this.allowBlank){
40497 var currency = this.getCurrency();
40499 if(this.validateValue(this.getRawValue()) && currency.length){
40504 this.markInvalid();
40508 getName: function()
40513 beforeBlur : function()
40519 var v = this.parseValue(this.getRawValue());
40526 onBlur : function()
40530 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40531 //this.el.removeClass(this.focusClass);
40534 this.hasFocus = false;
40536 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40540 var v = this.getValue();
40542 if(String(v) !== String(this.startValue)){
40543 this.fireEvent('change', this, v, this.startValue);
40546 this.fireEvent("blur", this);
40549 inputEl : function()
40551 return this.el.select('.roo-money-amount-input', true).first();
40554 currencyEl : function()
40556 return this.el.select('.roo-money-currency-input', true).first();