2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets, function(s) {
10 if ( s.href && s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass(['hidden','d-none']);
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass(['hidden','d-none']);
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fa
593 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
594 * @cfg {String} badge text for badge
595 * @cfg {String} theme (default|glow)
596 * @cfg {Boolean} inverse dark themed version
597 * @cfg {Boolean} toggle is it a slidy toggle button
598 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
599 * @cfg {String} ontext text for on slidy toggle state
600 * @cfg {String} offtext text for off slidy toggle state
601 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
602 * @cfg {Boolean} removeClass remove the standard class..
603 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
606 * Create a new button
607 * @param {Object} config The config object
611 Roo.bootstrap.Button = function(config){
612 Roo.bootstrap.Button.superclass.constructor.call(this, config);
613 this.weightClass = ["btn-default btn-outline-secondary",
625 * When a butotn is pressed
626 * @param {Roo.bootstrap.Button} btn
627 * @param {Roo.EventObject} e
632 * After the button has been toggles
633 * @param {Roo.bootstrap.Button} btn
634 * @param {Roo.EventObject} e
635 * @param {boolean} pressed (also available as button.pressed)
641 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
662 preventDefault: true,
670 getAutoCreate : function(){
678 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
679 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
684 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
686 if (this.toggle == true) {
689 cls: 'slider-frame roo-button',
694 'data-off-text':'OFF',
695 cls: 'slider-button',
701 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702 cfg.cls += ' '+this.weight;
711 cfg["aria-hidden"] = true;
713 cfg.html = "×";
719 if (this.theme==='default') {
720 cfg.cls = 'btn roo-button';
722 //if (this.parentType != 'Navbar') {
723 this.weight = this.weight.length ? this.weight : 'default';
725 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
727 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
728 var weight = this.weight == 'default' ? 'secondary' : this.weight;
729 cfg.cls += ' btn-' + outline + weight;
730 if (this.weight == 'default') {
732 cfg.cls += ' btn-' + this.weight;
735 } else if (this.theme==='glow') {
738 cfg.cls = 'btn-glow roo-button';
740 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
742 cfg.cls += ' ' + this.weight;
748 this.cls += ' inverse';
752 if (this.active || this.pressed === true) {
753 cfg.cls += ' active';
757 cfg.disabled = 'disabled';
761 Roo.log('changing to ul' );
763 this.glyphicon = 'caret';
764 if (Roo.bootstrap.version == 4) {
765 this.fa = 'caret-down';
770 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
772 //gsRoo.log(this.parentType);
773 if (this.parentType === 'Navbar' && !this.parent().bar) {
774 Roo.log('changing to li?');
783 href : this.href || '#'
786 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
787 cfg.cls += ' dropdown';
794 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
796 if (this.glyphicon) {
797 cfg.html = ' ' + cfg.html;
802 cls: 'glyphicon glyphicon-' + this.glyphicon
807 cfg.html = ' ' + cfg.html;
812 cls: 'fa fas fa-' + this.fa
822 // cfg.cls='btn roo-button';
826 var value = cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon,
838 cls: 'fa fas fa-' + this.fa,
843 var bw = this.badge_weight.length ? this.badge_weight :
844 (this.weight.length ? this.weight : 'secondary');
845 bw = bw == 'default' ? 'secondary' : bw;
851 cls: 'badge badge-' + bw,
860 cfg.cls += ' dropdown';
861 cfg.html = typeof(cfg.html) != 'undefined' ?
862 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
865 if (cfg.tag !== 'a' && this.href !== '') {
866 throw "Tag must be a to set href.";
867 } else if (this.href.length > 0) {
868 cfg.href = this.href;
871 if(this.removeClass){
876 cfg.target = this.target;
881 initEvents: function() {
882 // Roo.log('init events?');
883 // Roo.log(this.el.dom);
886 if (typeof (this.menu) != 'undefined') {
887 this.menu.parentType = this.xtype;
888 this.menu.triggerEl = this.el;
889 this.addxtype(Roo.apply({}, this.menu));
893 if (this.el.hasClass('roo-button')) {
894 this.el.on('click', this.onClick, this);
896 this.el.select('.roo-button').on('click', this.onClick, this);
899 if(this.removeClass){
900 this.el.on('click', this.onClick, this);
903 this.el.enableDisplayMode();
906 onClick : function(e)
912 Roo.log('button on click ');
913 if(this.preventDefault){
917 if (this.pressed === true || this.pressed === false) {
918 this.toggleActive(e);
922 this.fireEvent('click', this, e);
926 * Enables this button
930 this.disabled = false;
931 this.el.removeClass('disabled');
935 * Disable this button
939 this.disabled = true;
940 this.el.addClass('disabled');
943 * sets the active state on/off,
944 * @param {Boolean} state (optional) Force a particular state
946 setActive : function(v) {
948 this.el[v ? 'addClass' : 'removeClass']('active');
952 * toggles the current active state
954 toggleActive : function(e)
956 this.setActive(!this.pressed);
957 this.fireEvent('toggle', this, e, !this.pressed);
960 * get the current active state
961 * @return {boolean} true if it's active
963 isActive : function()
965 return this.el.hasClass('active');
968 * set the text of the first selected button
970 setText : function(str)
972 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
975 * get the text of the first selected button
979 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
982 setWeight : function(str)
984 this.el.removeClass(this.weightClass);
986 var outline = this.outline ? 'outline-' : '';
987 if (str == 'default') {
988 this.el.addClass('btn-default btn-outline-secondary');
991 this.el.addClass('btn-' + outline + str);
1005 * @class Roo.bootstrap.Column
1006 * @extends Roo.bootstrap.Component
1007 * Bootstrap Column class
1008 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1009 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1010 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1011 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1012 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1013 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1014 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1015 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1020 * @cfg {String} fa (ban|check|...) font awesome icon
1021 * @cfg {Number} fasize (1|2|....) font awsome size
1023 * @cfg {String} icon (info-sign|check|...) glyphicon name
1025 * @cfg {String} html content of column.
1028 * Create a new Column
1029 * @param {Object} config The config object
1032 Roo.bootstrap.Column = function(config){
1033 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1036 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1054 getAutoCreate : function(){
1055 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1063 ['xs','sm','md','lg'].map(function(size){
1064 //Roo.log( size + ':' + settings[size]);
1066 if (settings[size+'off'] !== false) {
1067 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1070 if (settings[size] === false) {
1074 if (!settings[size]) { // 0 = hidden
1075 cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
1078 cfg.cls += ' col-' + size + '-' + settings[size] + (
1079 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1085 cfg.cls += ' hidden';
1088 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1089 cfg.cls +=' alert alert-' + this.alert;
1093 if (this.html.length) {
1094 cfg.html = this.html;
1098 if (this.fasize > 1) {
1099 fasize = ' fa-' + this.fasize + 'x';
1101 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1106 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1125 * @class Roo.bootstrap.Container
1126 * @extends Roo.bootstrap.Component
1127 * Bootstrap Container class
1128 * @cfg {Boolean} jumbotron is it a jumbotron element
1129 * @cfg {String} html content of element
1130 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1131 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1132 * @cfg {String} header content of header (for panel)
1133 * @cfg {String} footer content of footer (for panel)
1134 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1135 * @cfg {String} tag (header|aside|section) type of HTML tag.
1136 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1137 * @cfg {String} fa font awesome icon
1138 * @cfg {String} icon (info-sign|check|...) glyphicon name
1139 * @cfg {Boolean} hidden (true|false) hide the element
1140 * @cfg {Boolean} expandable (true|false) default false
1141 * @cfg {Boolean} expanded (true|false) default true
1142 * @cfg {String} rheader contet on the right of header
1143 * @cfg {Boolean} clickable (true|false) default false
1147 * Create a new Container
1148 * @param {Object} config The config object
1151 Roo.bootstrap.Container = function(config){
1152 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1158 * After the panel has been expand
1160 * @param {Roo.bootstrap.Container} this
1165 * After the panel has been collapsed
1167 * @param {Roo.bootstrap.Container} this
1172 * When a element is chick
1173 * @param {Roo.bootstrap.Container} this
1174 * @param {Roo.EventObject} e
1180 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1198 getChildContainer : function() {
1204 if (this.panel.length) {
1205 return this.el.select('.panel-body',true).first();
1212 getAutoCreate : function(){
1215 tag : this.tag || 'div',
1219 if (this.jumbotron) {
1220 cfg.cls = 'jumbotron';
1225 // - this is applied by the parent..
1227 // cfg.cls = this.cls + '';
1230 if (this.sticky.length) {
1232 var bd = Roo.get(document.body);
1233 if (!bd.hasClass('bootstrap-sticky')) {
1234 bd.addClass('bootstrap-sticky');
1235 Roo.select('html',true).setStyle('height', '100%');
1238 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1242 if (this.well.length) {
1243 switch (this.well) {
1246 cfg.cls +=' well well-' +this.well;
1255 cfg.cls += ' hidden';
1259 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1260 cfg.cls +=' alert alert-' + this.alert;
1265 if (this.panel.length) {
1266 cfg.cls += ' panel panel-' + this.panel;
1268 if (this.header.length) {
1272 if(this.expandable){
1274 cfg.cls = cfg.cls + ' expandable';
1278 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1286 cls : 'panel-title',
1287 html : (this.expandable ? ' ' : '') + this.header
1291 cls: 'panel-header-right',
1297 cls : 'panel-heading',
1298 style : this.expandable ? 'cursor: pointer' : '',
1306 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1311 if (this.footer.length) {
1313 cls : 'panel-footer',
1322 body.html = this.html || cfg.html;
1323 // prefix with the icons..
1325 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1328 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1333 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1334 cfg.cls = 'container';
1340 initEvents: function()
1342 if(this.expandable){
1343 var headerEl = this.headerEl();
1346 headerEl.on('click', this.onToggleClick, this);
1351 this.el.on('click', this.onClick, this);
1356 onToggleClick : function()
1358 var headerEl = this.headerEl();
1374 if(this.fireEvent('expand', this)) {
1376 this.expanded = true;
1378 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1380 this.el.select('.panel-body',true).first().removeClass('hide');
1382 var toggleEl = this.toggleEl();
1388 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1393 collapse : function()
1395 if(this.fireEvent('collapse', this)) {
1397 this.expanded = false;
1399 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1400 this.el.select('.panel-body',true).first().addClass('hide');
1402 var toggleEl = this.toggleEl();
1408 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1412 toggleEl : function()
1414 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1418 return this.el.select('.panel-heading .fa',true).first();
1421 headerEl : function()
1423 if(!this.el || !this.panel.length || !this.header.length){
1427 return this.el.select('.panel-heading',true).first()
1432 if(!this.el || !this.panel.length){
1436 return this.el.select('.panel-body',true).first()
1439 titleEl : function()
1441 if(!this.el || !this.panel.length || !this.header.length){
1445 return this.el.select('.panel-title',true).first();
1448 setTitle : function(v)
1450 var titleEl = this.titleEl();
1456 titleEl.dom.innerHTML = v;
1459 getTitle : function()
1462 var titleEl = this.titleEl();
1468 return titleEl.dom.innerHTML;
1471 setRightTitle : function(v)
1473 var t = this.el.select('.panel-header-right',true).first();
1479 t.dom.innerHTML = v;
1482 onClick : function(e)
1486 this.fireEvent('click', this, e);
1499 * @class Roo.bootstrap.Img
1500 * @extends Roo.bootstrap.Component
1501 * Bootstrap Img class
1502 * @cfg {Boolean} imgResponsive false | true
1503 * @cfg {String} border rounded | circle | thumbnail
1504 * @cfg {String} src image source
1505 * @cfg {String} alt image alternative text
1506 * @cfg {String} href a tag href
1507 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1508 * @cfg {String} xsUrl xs image source
1509 * @cfg {String} smUrl sm image source
1510 * @cfg {String} mdUrl md image source
1511 * @cfg {String} lgUrl lg image source
1514 * Create a new Input
1515 * @param {Object} config The config object
1518 Roo.bootstrap.Img = function(config){
1519 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1525 * The img click event for the img.
1526 * @param {Roo.EventObject} e
1532 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1534 imgResponsive: true,
1544 getAutoCreate : function()
1546 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1547 return this.createSingleImg();
1552 cls: 'roo-image-responsive-group',
1557 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1559 if(!_this[size + 'Url']){
1565 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1566 html: _this.html || cfg.html,
1567 src: _this[size + 'Url']
1570 img.cls += ' roo-image-responsive-' + size;
1572 var s = ['xs', 'sm', 'md', 'lg'];
1574 s.splice(s.indexOf(size), 1);
1576 Roo.each(s, function(ss){
1577 img.cls += ' hidden-' + ss;
1580 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1581 cfg.cls += ' img-' + _this.border;
1585 cfg.alt = _this.alt;
1598 a.target = _this.target;
1602 cfg.cn.push((_this.href) ? a : img);
1609 createSingleImg : function()
1613 cls: (this.imgResponsive) ? 'img-responsive' : '',
1615 src : 'about:blank' // just incase src get's set to undefined?!?
1618 cfg.html = this.html || cfg.html;
1620 cfg.src = this.src || cfg.src;
1622 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1623 cfg.cls += ' img-' + this.border;
1640 a.target = this.target;
1645 return (this.href) ? a : cfg;
1648 initEvents: function()
1651 this.el.on('click', this.onClick, this);
1656 onClick : function(e)
1658 Roo.log('img onclick');
1659 this.fireEvent('click', this, e);
1662 * Sets the url of the image - used to update it
1663 * @param {String} url the url of the image
1666 setSrc : function(url)
1670 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1671 this.el.dom.src = url;
1675 this.el.select('img', true).first().dom.src = url;
1691 * @class Roo.bootstrap.Link
1692 * @extends Roo.bootstrap.Component
1693 * Bootstrap Link Class
1694 * @cfg {String} alt image alternative text
1695 * @cfg {String} href a tag href
1696 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1697 * @cfg {String} html the content of the link.
1698 * @cfg {String} anchor name for the anchor link
1699 * @cfg {String} fa - favicon
1701 * @cfg {Boolean} preventDefault (true | false) default false
1705 * Create a new Input
1706 * @param {Object} config The config object
1709 Roo.bootstrap.Link = function(config){
1710 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1716 * The img click event for the img.
1717 * @param {Roo.EventObject} e
1723 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1727 preventDefault: false,
1733 getAutoCreate : function()
1735 var html = this.html || '';
1737 if (this.fa !== false) {
1738 html = '<i class="fa fa-' + this.fa + '"></i>';
1743 // anchor's do not require html/href...
1744 if (this.anchor === false) {
1746 cfg.href = this.href || '#';
1748 cfg.name = this.anchor;
1749 if (this.html !== false || this.fa !== false) {
1752 if (this.href !== false) {
1753 cfg.href = this.href;
1757 if(this.alt !== false){
1762 if(this.target !== false) {
1763 cfg.target = this.target;
1769 initEvents: function() {
1771 if(!this.href || this.preventDefault){
1772 this.el.on('click', this.onClick, this);
1776 onClick : function(e)
1778 if(this.preventDefault){
1781 //Roo.log('img onclick');
1782 this.fireEvent('click', this, e);
1795 * @class Roo.bootstrap.Header
1796 * @extends Roo.bootstrap.Component
1797 * Bootstrap Header class
1798 * @cfg {String} html content of header
1799 * @cfg {Number} level (1|2|3|4|5|6) default 1
1802 * Create a new Header
1803 * @param {Object} config The config object
1807 Roo.bootstrap.Header = function(config){
1808 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1811 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1819 getAutoCreate : function(){
1824 tag: 'h' + (1 *this.level),
1825 html: this.html || ''
1837 * Ext JS Library 1.1.1
1838 * Copyright(c) 2006-2007, Ext JS, LLC.
1840 * Originally Released Under LGPL - original licence link has changed is not relivant.
1843 * <script type="text/javascript">
1847 * @class Roo.bootstrap.MenuMgr
1848 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1851 Roo.bootstrap.MenuMgr = function(){
1852 var menus, active, groups = {}, attached = false, lastShow = new Date();
1854 // private - called when first menu is created
1857 active = new Roo.util.MixedCollection();
1858 Roo.get(document).addKeyListener(27, function(){
1859 if(active.length > 0){
1867 if(active && active.length > 0){
1868 var c = active.clone();
1878 if(active.length < 1){
1879 Roo.get(document).un("mouseup", onMouseDown);
1887 var last = active.last();
1888 lastShow = new Date();
1891 Roo.get(document).on("mouseup", onMouseDown);
1896 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1897 m.parentMenu.activeChild = m;
1898 }else if(last && last.isVisible()){
1899 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1904 function onBeforeHide(m){
1906 m.activeChild.hide();
1908 if(m.autoHideTimer){
1909 clearTimeout(m.autoHideTimer);
1910 delete m.autoHideTimer;
1915 function onBeforeShow(m){
1916 var pm = m.parentMenu;
1917 if(!pm && !m.allowOtherMenus){
1919 }else if(pm && pm.activeChild && active != m){
1920 pm.activeChild.hide();
1924 // private this should really trigger on mouseup..
1925 function onMouseDown(e){
1926 Roo.log("on Mouse Up");
1928 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1929 Roo.log("MenuManager hideAll");
1938 function onBeforeCheck(mi, state){
1940 var g = groups[mi.group];
1941 for(var i = 0, l = g.length; i < l; i++){
1943 g[i].setChecked(false);
1952 * Hides all menus that are currently visible
1954 hideAll : function(){
1959 register : function(menu){
1963 menus[menu.id] = menu;
1964 menu.on("beforehide", onBeforeHide);
1965 menu.on("hide", onHide);
1966 menu.on("beforeshow", onBeforeShow);
1967 menu.on("show", onShow);
1969 if(g && menu.events["checkchange"]){
1973 groups[g].push(menu);
1974 menu.on("checkchange", onCheck);
1979 * Returns a {@link Roo.menu.Menu} object
1980 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1981 * be used to generate and return a new Menu instance.
1983 get : function(menu){
1984 if(typeof menu == "string"){ // menu id
1986 }else if(menu.events){ // menu instance
1989 /*else if(typeof menu.length == 'number'){ // array of menu items?
1990 return new Roo.bootstrap.Menu({items:menu});
1991 }else{ // otherwise, must be a config
1992 return new Roo.bootstrap.Menu(menu);
1999 unregister : function(menu){
2000 delete menus[menu.id];
2001 menu.un("beforehide", onBeforeHide);
2002 menu.un("hide", onHide);
2003 menu.un("beforeshow", onBeforeShow);
2004 menu.un("show", onShow);
2006 if(g && menu.events["checkchange"]){
2007 groups[g].remove(menu);
2008 menu.un("checkchange", onCheck);
2013 registerCheckable : function(menuItem){
2014 var g = menuItem.group;
2019 groups[g].push(menuItem);
2020 menuItem.on("beforecheckchange", onBeforeCheck);
2025 unregisterCheckable : function(menuItem){
2026 var g = menuItem.group;
2028 groups[g].remove(menuItem);
2029 menuItem.un("beforecheckchange", onBeforeCheck);
2041 * @class Roo.bootstrap.Menu
2042 * @extends Roo.bootstrap.Component
2043 * Bootstrap Menu class - container for MenuItems
2044 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2045 * @cfg {bool} hidden if the menu should be hidden when rendered.
2046 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2047 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2051 * @param {Object} config The config object
2055 Roo.bootstrap.Menu = function(config){
2056 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2057 if (this.registerMenu && this.type != 'treeview') {
2058 Roo.bootstrap.MenuMgr.register(this);
2065 * Fires before this menu is displayed (return false to block)
2066 * @param {Roo.menu.Menu} this
2071 * Fires before this menu is hidden (return false to block)
2072 * @param {Roo.menu.Menu} this
2077 * Fires after this menu is displayed
2078 * @param {Roo.menu.Menu} this
2083 * Fires after this menu is hidden
2084 * @param {Roo.menu.Menu} this
2089 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2090 * @param {Roo.menu.Menu} this
2091 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2092 * @param {Roo.EventObject} e
2097 * Fires when the mouse is hovering over this menu
2098 * @param {Roo.menu.Menu} this
2099 * @param {Roo.EventObject} e
2100 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2105 * Fires when the mouse exits this menu
2106 * @param {Roo.menu.Menu} this
2107 * @param {Roo.EventObject} e
2108 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2113 * Fires when a menu item contained in this menu is clicked
2114 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2115 * @param {Roo.EventObject} e
2119 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2122 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2126 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2129 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2131 registerMenu : true,
2133 menuItems :false, // stores the menu items..
2143 getChildContainer : function() {
2147 getAutoCreate : function(){
2149 //if (['right'].indexOf(this.align)!==-1) {
2150 // cfg.cn[1].cls += ' pull-right'
2156 cls : 'dropdown-menu' ,
2157 style : 'z-index:1000'
2161 if (this.type === 'submenu') {
2162 cfg.cls = 'submenu active';
2164 if (this.type === 'treeview') {
2165 cfg.cls = 'treeview-menu';
2170 initEvents : function() {
2172 // Roo.log("ADD event");
2173 // Roo.log(this.triggerEl.dom);
2175 this.triggerEl.on('click', this.onTriggerClick, this);
2177 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2180 if (this.triggerEl.hasClass('nav-item')) {
2181 // dropdown toggle on the 'a' in BS4?
2182 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2184 this.triggerEl.addClass('dropdown-toggle');
2187 this.el.on('touchstart' , this.onTouch, this);
2189 this.el.on('click' , this.onClick, this);
2191 this.el.on("mouseover", this.onMouseOver, this);
2192 this.el.on("mouseout", this.onMouseOut, this);
2196 findTargetItem : function(e)
2198 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2202 //Roo.log(t); Roo.log(t.id);
2204 //Roo.log(this.menuitems);
2205 return this.menuitems.get(t.id);
2207 //return this.items.get(t.menuItemId);
2213 onTouch : function(e)
2215 Roo.log("menu.onTouch");
2216 //e.stopEvent(); this make the user popdown broken
2220 onClick : function(e)
2222 Roo.log("menu.onClick");
2224 var t = this.findTargetItem(e);
2225 if(!t || t.isContainer){
2230 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2231 if(t == this.activeItem && t.shouldDeactivate(e)){
2232 this.activeItem.deactivate();
2233 delete this.activeItem;
2237 this.setActiveItem(t, true);
2245 Roo.log('pass click event');
2249 this.fireEvent("click", this, t, e);
2253 if(!t.href.length || t.href == '#'){
2254 (function() { _this.hide(); }).defer(100);
2259 onMouseOver : function(e){
2260 var t = this.findTargetItem(e);
2263 // if(t.canActivate && !t.disabled){
2264 // this.setActiveItem(t, true);
2268 this.fireEvent("mouseover", this, e, t);
2270 isVisible : function(){
2271 return !this.hidden;
2273 onMouseOut : function(e){
2274 var t = this.findTargetItem(e);
2277 // if(t == this.activeItem && t.shouldDeactivate(e)){
2278 // this.activeItem.deactivate();
2279 // delete this.activeItem;
2282 this.fireEvent("mouseout", this, e, t);
2287 * Displays this menu relative to another element
2288 * @param {String/HTMLElement/Roo.Element} element The element to align to
2289 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2290 * the element (defaults to this.defaultAlign)
2291 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2293 show : function(el, pos, parentMenu)
2295 if (false === this.fireEvent("beforeshow", this)) {
2296 Roo.log("show canceled");
2299 this.parentMenu = parentMenu;
2304 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2307 * Displays this menu at a specific xy position
2308 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2309 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2311 showAt : function(xy, parentMenu, /* private: */_e){
2312 this.parentMenu = parentMenu;
2317 this.fireEvent("beforeshow", this);
2318 //xy = this.el.adjustForConstraints(xy);
2322 this.hideMenuItems();
2323 this.hidden = false;
2324 this.triggerEl.addClass('open');
2325 this.el.addClass('show');
2327 // reassign x when hitting right
2328 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2329 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2332 // reassign y when hitting bottom
2333 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2334 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2337 // but the list may align on trigger left or trigger top... should it be a properity?
2339 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2344 this.fireEvent("show", this);
2350 this.doFocus.defer(50, this);
2354 doFocus : function(){
2356 this.focusEl.focus();
2361 * Hides this menu and optionally all parent menus
2362 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2364 hide : function(deep)
2366 if (false === this.fireEvent("beforehide", this)) {
2367 Roo.log("hide canceled");
2370 this.hideMenuItems();
2371 if(this.el && this.isVisible()){
2373 if(this.activeItem){
2374 this.activeItem.deactivate();
2375 this.activeItem = null;
2377 this.triggerEl.removeClass('open');;
2378 this.el.removeClass('show');
2380 this.fireEvent("hide", this);
2382 if(deep === true && this.parentMenu){
2383 this.parentMenu.hide(true);
2387 onTriggerClick : function(e)
2389 Roo.log('trigger click');
2391 var target = e.getTarget();
2393 Roo.log(target.nodeName.toLowerCase());
2395 if(target.nodeName.toLowerCase() === 'i'){
2401 onTriggerPress : function(e)
2403 Roo.log('trigger press');
2404 //Roo.log(e.getTarget());
2405 // Roo.log(this.triggerEl.dom);
2407 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2408 var pel = Roo.get(e.getTarget());
2409 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2410 Roo.log('is treeview or dropdown?');
2414 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2418 if (this.isVisible()) {
2423 this.show(this.triggerEl, '?', false);
2426 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2433 hideMenuItems : function()
2435 Roo.log("hide Menu Items");
2440 this.el.select('.open',true).each(function(aa) {
2442 aa.removeClass('open');
2446 addxtypeChild : function (tree, cntr) {
2447 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2449 this.menuitems.add(comp);
2461 this.getEl().dom.innerHTML = '';
2462 this.menuitems.clear();
2476 * @class Roo.bootstrap.MenuItem
2477 * @extends Roo.bootstrap.Component
2478 * Bootstrap MenuItem class
2479 * @cfg {String} html the menu label
2480 * @cfg {String} href the link
2481 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2482 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2483 * @cfg {Boolean} active used on sidebars to highlight active itesm
2484 * @cfg {String} fa favicon to show on left of menu item.
2485 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2489 * Create a new MenuItem
2490 * @param {Object} config The config object
2494 Roo.bootstrap.MenuItem = function(config){
2495 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2500 * The raw click event for the entire grid.
2501 * @param {Roo.bootstrap.MenuItem} this
2502 * @param {Roo.EventObject} e
2508 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2512 preventDefault: false,
2513 isContainer : false,
2517 getAutoCreate : function(){
2519 if(this.isContainer){
2522 cls: 'dropdown-menu-item '
2532 cls : 'dropdown-item',
2537 if (this.fa !== false) {
2540 cls : 'fa fa-' + this.fa
2549 cls: 'dropdown-menu-item',
2552 if (this.parent().type == 'treeview') {
2553 cfg.cls = 'treeview-menu';
2556 cfg.cls += ' active';
2561 anc.href = this.href || cfg.cn[0].href ;
2562 ctag.html = this.html || cfg.cn[0].html ;
2566 initEvents: function()
2568 if (this.parent().type == 'treeview') {
2569 this.el.select('a').on('click', this.onClick, this);
2573 this.menu.parentType = this.xtype;
2574 this.menu.triggerEl = this.el;
2575 this.menu = this.addxtype(Roo.apply({}, this.menu));
2579 onClick : function(e)
2581 Roo.log('item on click ');
2583 if(this.preventDefault){
2586 //this.parent().hideMenuItems();
2588 this.fireEvent('click', this, e);
2607 * @class Roo.bootstrap.MenuSeparator
2608 * @extends Roo.bootstrap.Component
2609 * Bootstrap MenuSeparator class
2612 * Create a new MenuItem
2613 * @param {Object} config The config object
2617 Roo.bootstrap.MenuSeparator = function(config){
2618 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2621 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2623 getAutoCreate : function(){
2642 * @class Roo.bootstrap.Modal
2643 * @extends Roo.bootstrap.Component
2644 * Bootstrap Modal class
2645 * @cfg {String} title Title of dialog
2646 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2647 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2648 * @cfg {Boolean} specificTitle default false
2649 * @cfg {Array} buttons Array of buttons or standard button set..
2650 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2651 * @cfg {Boolean} animate default true
2652 * @cfg {Boolean} allow_close default true
2653 * @cfg {Boolean} fitwindow default false
2654 * @cfg {Number} width fixed width - usefull for chrome extension only really.
2655 * @cfg {Number} height fixed height - usefull for chrome extension only really.
2656 * @cfg {String} size (sm|lg) default empty
2657 * @cfg {Number} max_width set the max width of modal
2661 * Create a new Modal Dialog
2662 * @param {Object} config The config object
2665 Roo.bootstrap.Modal = function(config){
2666 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2671 * The raw btnclick event for the button
2672 * @param {Roo.EventObject} e
2677 * Fire when dialog resize
2678 * @param {Roo.bootstrap.Modal} this
2679 * @param {Roo.EventObject} e
2683 this.buttons = this.buttons || [];
2686 this.tmpl = Roo.factory(this.tmpl);
2691 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2693 title : 'test dialog',
2703 specificTitle: false,
2705 buttonPosition: 'right',
2728 onRender : function(ct, position)
2730 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2733 var cfg = Roo.apply({}, this.getAutoCreate());
2736 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2738 //if (!cfg.name.length) {
2742 cfg.cls += ' ' + this.cls;
2745 cfg.style = this.style;
2747 this.el = Roo.get(document.body).createChild(cfg, position);
2749 //var type = this.el.dom.type;
2752 if(this.tabIndex !== undefined){
2753 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2756 this.dialogEl = this.el.select('.modal-dialog',true).first();
2757 this.bodyEl = this.el.select('.modal-body',true).first();
2758 this.closeEl = this.el.select('.modal-header .close', true).first();
2759 this.headerEl = this.el.select('.modal-header',true).first();
2760 this.titleEl = this.el.select('.modal-title',true).first();
2761 this.footerEl = this.el.select('.modal-footer',true).first();
2763 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2765 //this.el.addClass("x-dlg-modal");
2767 if (this.buttons.length) {
2768 Roo.each(this.buttons, function(bb) {
2769 var b = Roo.apply({}, bb);
2770 b.xns = b.xns || Roo.bootstrap;
2771 b.xtype = b.xtype || 'Button';
2772 if (typeof(b.listeners) == 'undefined') {
2773 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2776 var btn = Roo.factory(b);
2778 btn.render(this.getButtonContainer());
2782 // render the children.
2785 if(typeof(this.items) != 'undefined'){
2786 var items = this.items;
2789 for(var i =0;i < items.length;i++) {
2790 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2794 this.items = nitems;
2796 // where are these used - they used to be body/close/footer
2800 //this.el.addClass([this.fieldClass, this.cls]);
2804 getAutoCreate : function()
2806 // we will default to modal-body-overflow - might need to remove or make optional later.
2808 cls : 'modal-body enable-modal-body-overflow ',
2809 html : this.html || ''
2814 cls : 'modal-title',
2818 if(this.specificTitle){
2824 if (this.allow_close && Roo.bootstrap.version == 3) {
2834 if (this.allow_close && Roo.bootstrap.version == 4) {
2844 if(this.size.length){
2845 size = 'modal-' + this.size;
2848 var footer = Roo.bootstrap.version == 3 ?
2850 cls : 'modal-footer',
2854 cls: 'btn-' + this.buttonPosition
2859 { // BS4 uses mr-auto on left buttons....
2860 cls : 'modal-footer'
2871 cls: "modal-dialog " + size,
2874 cls : "modal-content",
2877 cls : 'modal-header',
2892 modal.cls += ' fade';
2898 getChildContainer : function() {
2903 getButtonContainer : function() {
2905 return Roo.bootstrap.version == 4 ?
2906 this.el.select('.modal-footer',true).first()
2907 : this.el.select('.modal-footer div',true).first();
2910 initEvents : function()
2912 if (this.allow_close) {
2913 this.closeEl.on('click', this.hide, this);
2915 Roo.EventManager.onWindowResize(this.resize, this, true);
2923 this.maskEl.setSize(
2924 Roo.lib.Dom.getViewWidth(true),
2925 Roo.lib.Dom.getViewHeight(true)
2928 if (this.fitwindow) {
2932 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2933 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2938 if(this.max_width !== 0) {
2940 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2943 this.setSize(w, this.height);
2947 if(this.max_height) {
2948 this.setSize(w,Math.min(
2950 Roo.lib.Dom.getViewportHeight(true) - 60
2956 if(!this.fit_content) {
2957 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2961 this.setSize(w, Math.min(
2963 this.headerEl.getHeight() +
2964 this.footerEl.getHeight() +
2965 this.getChildHeight(this.bodyEl.dom.childNodes),
2966 Roo.lib.Dom.getViewportHeight(true) - 60)
2972 setSize : function(w,h)
2983 if (!this.rendered) {
2987 //this.el.setStyle('display', 'block');
2988 this.el.removeClass('hideing');
2989 this.el.dom.style.display='block';
2991 Roo.get(document.body).addClass('modal-open');
2993 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2996 this.el.addClass('show');
2997 this.el.addClass('in');
3000 this.el.addClass('show');
3001 this.el.addClass('in');
3004 // not sure how we can show data in here..
3006 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3009 Roo.get(document.body).addClass("x-body-masked");
3011 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3012 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3013 this.maskEl.dom.style.display = 'block';
3014 this.maskEl.addClass('show');
3019 this.fireEvent('show', this);
3021 // set zindex here - otherwise it appears to be ignored...
3022 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3025 this.items.forEach( function(e) {
3026 e.layout ? e.layout() : false;
3034 if(this.fireEvent("beforehide", this) !== false){
3036 this.maskEl.removeClass('show');
3038 this.maskEl.dom.style.display = '';
3039 Roo.get(document.body).removeClass("x-body-masked");
3040 this.el.removeClass('in');
3041 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3043 if(this.animate){ // why
3044 this.el.addClass('hideing');
3045 this.el.removeClass('show');
3047 if (!this.el.hasClass('hideing')) {
3048 return; // it's been shown again...
3051 this.el.dom.style.display='';
3053 Roo.get(document.body).removeClass('modal-open');
3054 this.el.removeClass('hideing');
3058 this.el.removeClass('show');
3059 this.el.dom.style.display='';
3060 Roo.get(document.body).removeClass('modal-open');
3063 this.fireEvent('hide', this);
3066 isVisible : function()
3069 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3073 addButton : function(str, cb)
3077 var b = Roo.apply({}, { html : str } );
3078 b.xns = b.xns || Roo.bootstrap;
3079 b.xtype = b.xtype || 'Button';
3080 if (typeof(b.listeners) == 'undefined') {
3081 b.listeners = { click : cb.createDelegate(this) };
3084 var btn = Roo.factory(b);
3086 btn.render(this.getButtonContainer());
3092 setDefaultButton : function(btn)
3094 //this.el.select('.modal-footer').()
3097 resizeTo: function(w,h)
3099 this.dialogEl.setWidth(w);
3101 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3103 this.bodyEl.setHeight(h - diff);
3105 this.fireEvent('resize', this);
3108 setContentSize : function(w, h)
3112 onButtonClick: function(btn,e)
3115 this.fireEvent('btnclick', btn.name, e);
3118 * Set the title of the Dialog
3119 * @param {String} str new Title
3121 setTitle: function(str) {
3122 this.titleEl.dom.innerHTML = str;
3125 * Set the body of the Dialog
3126 * @param {String} str new Title
3128 setBody: function(str) {
3129 this.bodyEl.dom.innerHTML = str;
3132 * Set the body of the Dialog using the template
3133 * @param {Obj} data - apply this data to the template and replace the body contents.
3135 applyBody: function(obj)
3138 Roo.log("Error - using apply Body without a template");
3141 this.tmpl.overwrite(this.bodyEl, obj);
3144 getChildHeight : function(child_nodes)
3148 child_nodes.length == 0
3153 var child_height = 0;
3155 for(var i = 0; i < child_nodes.length; i++) {
3158 * for modal with tabs...
3159 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3161 var layout_childs = child_nodes[i].childNodes;
3163 for(var j = 0; j < layout_childs.length; j++) {
3165 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3167 var layout_body_childs = layout_childs[j].childNodes;
3169 for(var k = 0; k < layout_body_childs.length; k++) {
3171 if(layout_body_childs[k].classList.contains('navbar')) {
3172 child_height += layout_body_childs[k].offsetHeight;
3176 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3178 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3180 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3182 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3183 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3198 child_height += child_nodes[i].offsetHeight;
3199 // Roo.log(child_nodes[i].offsetHeight);
3202 return child_height;
3208 Roo.apply(Roo.bootstrap.Modal, {
3210 * Button config that displays a single OK button
3219 * Button config that displays Yes and No buttons
3235 * Button config that displays OK and Cancel buttons
3250 * Button config that displays Yes, No and Cancel buttons
3274 * messagebox - can be used as a replace
3278 * @class Roo.MessageBox
3279 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3283 Roo.Msg.alert('Status', 'Changes saved successfully.');
3285 // Prompt for user data:
3286 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3288 // process text value...
3292 // Show a dialog using config options:
3294 title:'Save Changes?',
3295 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3296 buttons: Roo.Msg.YESNOCANCEL,
3303 Roo.bootstrap.MessageBox = function(){
3304 var dlg, opt, mask, waitTimer;
3305 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3306 var buttons, activeTextEl, bwidth;
3310 var handleButton = function(button){
3312 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3316 var handleHide = function(){
3318 dlg.el.removeClass(opt.cls);
3321 // Roo.TaskMgr.stop(waitTimer);
3322 // waitTimer = null;
3327 var updateButtons = function(b){
3330 buttons["ok"].hide();
3331 buttons["cancel"].hide();
3332 buttons["yes"].hide();
3333 buttons["no"].hide();
3334 dlg.footerEl.hide();
3338 dlg.footerEl.show();
3339 for(var k in buttons){
3340 if(typeof buttons[k] != "function"){
3343 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3344 width += buttons[k].el.getWidth()+15;
3354 var handleEsc = function(d, k, e){
3355 if(opt && opt.closable !== false){
3365 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3366 * @return {Roo.BasicDialog} The BasicDialog element
3368 getDialog : function(){
3370 dlg = new Roo.bootstrap.Modal( {
3373 //constraintoviewport:false,
3375 //collapsible : false,
3380 //buttonAlign:"center",
3381 closeClick : function(){
3382 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3385 handleButton("cancel");
3390 dlg.on("hide", handleHide);
3392 //dlg.addKeyListener(27, handleEsc);
3394 this.buttons = buttons;
3395 var bt = this.buttonText;
3396 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3397 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3398 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3399 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3401 bodyEl = dlg.bodyEl.createChild({
3403 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3404 '<textarea class="roo-mb-textarea"></textarea>' +
3405 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3407 msgEl = bodyEl.dom.firstChild;
3408 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3409 textboxEl.enableDisplayMode();
3410 textboxEl.addKeyListener([10,13], function(){
3411 if(dlg.isVisible() && opt && opt.buttons){
3414 }else if(opt.buttons.yes){
3415 handleButton("yes");
3419 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3420 textareaEl.enableDisplayMode();
3421 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3422 progressEl.enableDisplayMode();
3424 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3425 var pf = progressEl.dom.firstChild;
3427 pp = Roo.get(pf.firstChild);
3428 pp.setHeight(pf.offsetHeight);
3436 * Updates the message box body text
3437 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3438 * the XHTML-compliant non-breaking space character '&#160;')
3439 * @return {Roo.MessageBox} This message box
3441 updateText : function(text)
3443 if(!dlg.isVisible() && !opt.width){
3444 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3445 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3447 msgEl.innerHTML = text || ' ';
3449 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3450 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3452 Math.min(opt.width || cw , this.maxWidth),
3453 Math.max(opt.minWidth || this.minWidth, bwidth)
3456 activeTextEl.setWidth(w);
3458 if(dlg.isVisible()){
3459 dlg.fixedcenter = false;
3461 // to big, make it scroll. = But as usual stupid IE does not support
3464 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3465 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3466 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3468 bodyEl.dom.style.height = '';
3469 bodyEl.dom.style.overflowY = '';
3472 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3474 bodyEl.dom.style.overflowX = '';
3477 dlg.setContentSize(w, bodyEl.getHeight());
3478 if(dlg.isVisible()){
3479 dlg.fixedcenter = true;
3485 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3486 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3487 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3488 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3489 * @return {Roo.MessageBox} This message box
3491 updateProgress : function(value, text){
3493 this.updateText(text);
3496 if (pp) { // weird bug on my firefox - for some reason this is not defined
3497 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3498 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3504 * Returns true if the message box is currently displayed
3505 * @return {Boolean} True if the message box is visible, else false
3507 isVisible : function(){
3508 return dlg && dlg.isVisible();
3512 * Hides the message box if it is displayed
3515 if(this.isVisible()){
3521 * Displays a new message box, or reinitializes an existing message box, based on the config options
3522 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3523 * The following config object properties are supported:
3525 Property Type Description
3526 ---------- --------------- ------------------------------------------------------------------------------------
3527 animEl String/Element An id or Element from which the message box should animate as it opens and
3528 closes (defaults to undefined)
3529 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3530 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3531 closable Boolean False to hide the top-right close button (defaults to true). Note that
3532 progress and wait dialogs will ignore this property and always hide the
3533 close button as they can only be closed programmatically.
3534 cls String A custom CSS class to apply to the message box element
3535 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3536 displayed (defaults to 75)
3537 fn Function A callback function to execute after closing the dialog. The arguments to the
3538 function will be btn (the name of the button that was clicked, if applicable,
3539 e.g. "ok"), and text (the value of the active text field, if applicable).
3540 Progress and wait dialogs will ignore this option since they do not respond to
3541 user actions and can only be closed programmatically, so any required function
3542 should be called by the same code after it closes the dialog.
3543 icon String A CSS class that provides a background image to be used as an icon for
3544 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3545 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3546 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3547 modal Boolean False to allow user interaction with the page while the message box is
3548 displayed (defaults to true)
3549 msg String A string that will replace the existing message box body text (defaults
3550 to the XHTML-compliant non-breaking space character ' ')
3551 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3552 progress Boolean True to display a progress bar (defaults to false)
3553 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3554 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3555 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3556 title String The title text
3557 value String The string value to set into the active textbox element if displayed
3558 wait Boolean True to display a progress bar (defaults to false)
3559 width Number The width of the dialog in pixels
3566 msg: 'Please enter your address:',
3568 buttons: Roo.MessageBox.OKCANCEL,
3571 animEl: 'addAddressBtn'
3574 * @param {Object} config Configuration options
3575 * @return {Roo.MessageBox} This message box
3577 show : function(options)
3580 // this causes nightmares if you show one dialog after another
3581 // especially on callbacks..
3583 if(this.isVisible()){
3586 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3587 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3588 Roo.log("New Dialog Message:" + options.msg )
3589 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3590 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3593 var d = this.getDialog();
3595 d.setTitle(opt.title || " ");
3596 d.closeEl.setDisplayed(opt.closable !== false);
3597 activeTextEl = textboxEl;
3598 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3603 textareaEl.setHeight(typeof opt.multiline == "number" ?
3604 opt.multiline : this.defaultTextHeight);
3605 activeTextEl = textareaEl;
3614 progressEl.setDisplayed(opt.progress === true);
3616 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3618 this.updateProgress(0);
3619 activeTextEl.dom.value = opt.value || "";
3621 dlg.setDefaultButton(activeTextEl);
3623 var bs = opt.buttons;
3627 }else if(bs && bs.yes){
3628 db = buttons["yes"];
3630 dlg.setDefaultButton(db);
3632 bwidth = updateButtons(opt.buttons);
3633 this.updateText(opt.msg);
3635 d.el.addClass(opt.cls);
3637 d.proxyDrag = opt.proxyDrag === true;
3638 d.modal = opt.modal !== false;
3639 d.mask = opt.modal !== false ? mask : false;
3641 // force it to the end of the z-index stack so it gets a cursor in FF
3642 document.body.appendChild(dlg.el.dom);
3643 d.animateTarget = null;
3644 d.show(options.animEl);
3650 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3651 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3652 * and closing the message box when the process is complete.
3653 * @param {String} title The title bar text
3654 * @param {String} msg The message box body text
3655 * @return {Roo.MessageBox} This message box
3657 progress : function(title, msg){
3664 minWidth: this.minProgressWidth,
3671 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3672 * If a callback function is passed it will be called after the user clicks the button, and the
3673 * id of the button that was clicked will be passed as the only parameter to the callback
3674 * (could also be the top-right close button).
3675 * @param {String} title The title bar text
3676 * @param {String} msg The message box body text
3677 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3678 * @param {Object} scope (optional) The scope of the callback function
3679 * @return {Roo.MessageBox} This message box
3681 alert : function(title, msg, fn, scope)
3696 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3697 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3698 * You are responsible for closing the message box when the process is complete.
3699 * @param {String} msg The message box body text
3700 * @param {String} title (optional) The title bar text
3701 * @return {Roo.MessageBox} This message box
3703 wait : function(msg, title){
3714 waitTimer = Roo.TaskMgr.start({
3716 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3724 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3725 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3726 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3727 * @param {String} title The title bar text
3728 * @param {String} msg The message box body text
3729 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3730 * @param {Object} scope (optional) The scope of the callback function
3731 * @return {Roo.MessageBox} This message box
3733 confirm : function(title, msg, fn, scope){
3737 buttons: this.YESNO,
3746 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3747 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3748 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3749 * (could also be the top-right close button) and the text that was entered will be passed as the two
3750 * parameters to the callback.
3751 * @param {String} title The title bar text
3752 * @param {String} msg The message box body text
3753 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3754 * @param {Object} scope (optional) The scope of the callback function
3755 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3756 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3757 * @return {Roo.MessageBox} This message box
3759 prompt : function(title, msg, fn, scope, multiline){
3763 buttons: this.OKCANCEL,
3768 multiline: multiline,
3775 * Button config that displays a single OK button
3780 * Button config that displays Yes and No buttons
3783 YESNO : {yes:true, no:true},
3785 * Button config that displays OK and Cancel buttons
3788 OKCANCEL : {ok:true, cancel:true},
3790 * Button config that displays Yes, No and Cancel buttons
3793 YESNOCANCEL : {yes:true, no:true, cancel:true},
3796 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3799 defaultTextHeight : 75,
3801 * The maximum width in pixels of the message box (defaults to 600)
3806 * The minimum width in pixels of the message box (defaults to 100)
3811 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3812 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3815 minProgressWidth : 250,
3817 * An object containing the default button text strings that can be overriden for localized language support.
3818 * Supported properties are: ok, cancel, yes and no.
3819 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3832 * Shorthand for {@link Roo.MessageBox}
3834 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3835 Roo.Msg = Roo.Msg || Roo.MessageBox;
3844 * @class Roo.bootstrap.Navbar
3845 * @extends Roo.bootstrap.Component
3846 * Bootstrap Navbar class
3849 * Create a new Navbar
3850 * @param {Object} config The config object
3854 Roo.bootstrap.Navbar = function(config){
3855 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3859 * @event beforetoggle
3860 * Fire before toggle the menu
3861 * @param {Roo.EventObject} e
3863 "beforetoggle" : true
3867 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3876 getAutoCreate : function(){
3879 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3883 initEvents :function ()
3885 //Roo.log(this.el.select('.navbar-toggle',true));
3886 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3893 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3895 var size = this.el.getSize();
3896 this.maskEl.setSize(size.width, size.height);
3897 this.maskEl.enableDisplayMode("block");
3906 getChildContainer : function()
3908 if (this.el && this.el.select('.collapse').getCount()) {
3909 return this.el.select('.collapse',true).first();
3924 onToggle : function()
3927 if(this.fireEvent('beforetoggle', this) === false){
3930 var ce = this.el.select('.navbar-collapse',true).first();
3932 if (!ce.hasClass('show')) {
3942 * Expand the navbar pulldown
3944 expand : function ()
3947 var ce = this.el.select('.navbar-collapse',true).first();
3948 if (ce.hasClass('collapsing')) {
3951 ce.dom.style.height = '';
3953 ce.addClass('in'); // old...
3954 ce.removeClass('collapse');
3955 ce.addClass('show');
3956 var h = ce.getHeight();
3958 ce.removeClass('show');
3959 // at this point we should be able to see it..
3960 ce.addClass('collapsing');
3962 ce.setHeight(0); // resize it ...
3963 ce.on('transitionend', function() {
3964 //Roo.log('done transition');
3965 ce.removeClass('collapsing');
3966 ce.addClass('show');
3967 ce.removeClass('collapse');
3969 ce.dom.style.height = '';
3970 }, this, { single: true} );
3972 ce.dom.scrollTop = 0;
3975 * Collapse the navbar pulldown
3977 collapse : function()
3979 var ce = this.el.select('.navbar-collapse',true).first();
3981 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
3982 // it's collapsed or collapsing..
3985 ce.removeClass('in'); // old...
3986 ce.setHeight(ce.getHeight());
3987 ce.removeClass('show');
3988 ce.addClass('collapsing');
3990 ce.on('transitionend', function() {
3991 ce.dom.style.height = '';
3992 ce.removeClass('collapsing');
3993 ce.addClass('collapse');
3994 }, this, { single: true} );
4014 * @class Roo.bootstrap.NavSimplebar
4015 * @extends Roo.bootstrap.Navbar
4016 * Bootstrap Sidebar class
4018 * @cfg {Boolean} inverse is inverted color
4020 * @cfg {String} type (nav | pills | tabs)
4021 * @cfg {Boolean} arrangement stacked | justified
4022 * @cfg {String} align (left | right) alignment
4024 * @cfg {Boolean} main (true|false) main nav bar? default false
4025 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4027 * @cfg {String} tag (header|footer|nav|div) default is nav
4029 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4033 * Create a new Sidebar
4034 * @param {Object} config The config object
4038 Roo.bootstrap.NavSimplebar = function(config){
4039 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4042 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4058 getAutoCreate : function(){
4062 tag : this.tag || 'div',
4063 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
4065 if (['light','white'].indexOf(this.weight) > -1) {
4066 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4068 cfg.cls += ' bg-' + this.weight;
4071 cfg.cls += ' navbar-inverse';
4075 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4077 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
4086 cls: 'nav nav-' + this.xtype,
4092 this.type = this.type || 'nav';
4093 if (['tabs','pills'].indexOf(this.type) != -1) {
4094 cfg.cn[0].cls += ' nav-' + this.type
4098 if (this.type!=='nav') {
4099 Roo.log('nav type must be nav/tabs/pills')
4101 cfg.cn[0].cls += ' navbar-nav'
4107 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4108 cfg.cn[0].cls += ' nav-' + this.arrangement;
4112 if (this.align === 'right') {
4113 cfg.cn[0].cls += ' navbar-right';
4138 * navbar-expand-md fixed-top
4142 * @class Roo.bootstrap.NavHeaderbar
4143 * @extends Roo.bootstrap.NavSimplebar
4144 * Bootstrap Sidebar class
4146 * @cfg {String} brand what is brand
4147 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4148 * @cfg {String} brand_href href of the brand
4149 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4150 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4151 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4152 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4155 * Create a new Sidebar
4156 * @param {Object} config The config object
4160 Roo.bootstrap.NavHeaderbar = function(config){
4161 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4165 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4172 desktopCenter : false,
4175 getAutoCreate : function(){
4178 tag: this.nav || 'nav',
4179 cls: 'navbar navbar-expand-md',
4185 if (this.desktopCenter) {
4186 cn.push({cls : 'container', cn : []});
4194 cls: 'navbar-toggle navbar-toggler',
4195 'data-toggle': 'collapse',
4200 html: 'Toggle navigation'
4204 cls: 'icon-bar navbar-toggler-icon'
4217 cn.push( Roo.bootstrap.version == 4 ? btn : {
4219 cls: 'navbar-header',
4228 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
4232 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4234 if (['light','white'].indexOf(this.weight) > -1) {
4235 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4237 cfg.cls += ' bg-' + this.weight;
4240 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4241 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4243 // tag can override this..
4245 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4248 if (this.brand !== '') {
4249 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4250 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4252 href: this.brand_href ? this.brand_href : '#',
4253 cls: 'navbar-brand',
4261 cfg.cls += ' main-nav';
4269 getHeaderChildContainer : function()
4271 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4272 return this.el.select('.navbar-header',true).first();
4275 return this.getChildContainer();
4279 initEvents : function()
4281 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4283 if (this.autohide) {
4288 Roo.get(document).on('scroll',function(e) {
4289 var ns = Roo.get(document).getScroll().top;
4290 var os = prevScroll;
4294 ft.removeClass('slideDown');
4295 ft.addClass('slideUp');
4298 ft.removeClass('slideUp');
4299 ft.addClass('slideDown');
4320 * @class Roo.bootstrap.NavSidebar
4321 * @extends Roo.bootstrap.Navbar
4322 * Bootstrap Sidebar class
4325 * Create a new Sidebar
4326 * @param {Object} config The config object
4330 Roo.bootstrap.NavSidebar = function(config){
4331 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4334 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4336 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4338 getAutoCreate : function(){
4343 cls: 'sidebar sidebar-nav'
4365 * @class Roo.bootstrap.NavGroup
4366 * @extends Roo.bootstrap.Component
4367 * Bootstrap NavGroup class
4368 * @cfg {String} align (left|right)
4369 * @cfg {Boolean} inverse
4370 * @cfg {String} type (nav|pills|tab) default nav
4371 * @cfg {String} navId - reference Id for navbar.
4375 * Create a new nav group
4376 * @param {Object} config The config object
4379 Roo.bootstrap.NavGroup = function(config){
4380 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4383 Roo.bootstrap.NavGroup.register(this);
4387 * Fires when the active item changes
4388 * @param {Roo.bootstrap.NavGroup} this
4389 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4390 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4397 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4408 getAutoCreate : function()
4410 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4416 if (Roo.bootstrap.version == 4) {
4417 if (['tabs','pills'].indexOf(this.type) != -1) {
4418 cfg.cls += ' nav-' + this.type;
4420 // trying to remove so header bar can right align top?
4421 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
4422 // do not use on header bar...
4423 cfg.cls += ' navbar-nav';
4428 if (['tabs','pills'].indexOf(this.type) != -1) {
4429 cfg.cls += ' nav-' + this.type
4431 if (this.type !== 'nav') {
4432 Roo.log('nav type must be nav/tabs/pills')
4434 cfg.cls += ' navbar-nav'
4438 if (this.parent() && this.parent().sidebar) {
4441 cls: 'dashboard-menu sidebar-menu'
4447 if (this.form === true) {
4450 cls: 'navbar-form form-inline'
4452 //nav navbar-right ml-md-auto
4453 if (this.align === 'right') {
4454 cfg.cls += ' navbar-right ml-md-auto';
4456 cfg.cls += ' navbar-left';
4460 if (this.align === 'right') {
4461 cfg.cls += ' navbar-right ml-md-auto';
4463 cfg.cls += ' mr-auto';
4467 cfg.cls += ' navbar-inverse';
4475 * sets the active Navigation item
4476 * @param {Roo.bootstrap.NavItem} the new current navitem
4478 setActiveItem : function(item)
4481 Roo.each(this.navItems, function(v){
4486 v.setActive(false, true);
4493 item.setActive(true, true);
4494 this.fireEvent('changed', this, item, prev);
4499 * gets the active Navigation item
4500 * @return {Roo.bootstrap.NavItem} the current navitem
4502 getActive : function()
4506 Roo.each(this.navItems, function(v){
4517 indexOfNav : function()
4521 Roo.each(this.navItems, function(v,i){
4532 * adds a Navigation item
4533 * @param {Roo.bootstrap.NavItem} the navitem to add
4535 addItem : function(cfg)
4537 if (this.form && Roo.bootstrap.version == 4) {
4540 var cn = new Roo.bootstrap.NavItem(cfg);
4542 cn.parentId = this.id;
4543 cn.onRender(this.el, null);
4547 * register a Navigation item
4548 * @param {Roo.bootstrap.NavItem} the navitem to add
4550 register : function(item)
4552 this.navItems.push( item);
4553 item.navId = this.navId;
4558 * clear all the Navigation item
4561 clearAll : function()
4564 this.el.dom.innerHTML = '';
4567 getNavItem: function(tabId)
4570 Roo.each(this.navItems, function(e) {
4571 if (e.tabId == tabId) {
4581 setActiveNext : function()
4583 var i = this.indexOfNav(this.getActive());
4584 if (i > this.navItems.length) {
4587 this.setActiveItem(this.navItems[i+1]);
4589 setActivePrev : function()
4591 var i = this.indexOfNav(this.getActive());
4595 this.setActiveItem(this.navItems[i-1]);
4597 clearWasActive : function(except) {
4598 Roo.each(this.navItems, function(e) {
4599 if (e.tabId != except.tabId && e.was_active) {
4600 e.was_active = false;
4607 getWasActive : function ()
4610 Roo.each(this.navItems, function(e) {
4625 Roo.apply(Roo.bootstrap.NavGroup, {
4629 * register a Navigation Group
4630 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4632 register : function(navgrp)
4634 this.groups[navgrp.navId] = navgrp;
4638 * fetch a Navigation Group based on the navigation ID
4639 * @param {string} the navgroup to add
4640 * @returns {Roo.bootstrap.NavGroup} the navgroup
4642 get: function(navId) {
4643 if (typeof(this.groups[navId]) == 'undefined') {
4645 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4647 return this.groups[navId] ;
4662 * @class Roo.bootstrap.NavItem
4663 * @extends Roo.bootstrap.Component
4664 * Bootstrap Navbar.NavItem class
4665 * @cfg {String} href link to
4666 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4668 * @cfg {String} html content of button
4669 * @cfg {String} badge text inside badge
4670 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4671 * @cfg {String} glyphicon DEPRICATED - use fa
4672 * @cfg {String} icon DEPRICATED - use fa
4673 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4674 * @cfg {Boolean} active Is item active
4675 * @cfg {Boolean} disabled Is item disabled
4677 * @cfg {Boolean} preventDefault (true | false) default false
4678 * @cfg {String} tabId the tab that this item activates.
4679 * @cfg {String} tagtype (a|span) render as a href or span?
4680 * @cfg {Boolean} animateRef (true|false) link to element default false
4683 * Create a new Navbar Item
4684 * @param {Object} config The config object
4686 Roo.bootstrap.NavItem = function(config){
4687 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4692 * The raw click event for the entire grid.
4693 * @param {Roo.EventObject} e
4698 * Fires when the active item active state changes
4699 * @param {Roo.bootstrap.NavItem} this
4700 * @param {boolean} state the new state
4706 * Fires when scroll to element
4707 * @param {Roo.bootstrap.NavItem} this
4708 * @param {Object} options
4709 * @param {Roo.EventObject} e
4717 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4726 preventDefault : false,
4734 button_outline : false,
4738 getAutoCreate : function(){
4746 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4748 if (this.disabled) {
4749 cfg.cls += ' disabled';
4753 if (this.button_weight.length) {
4754 cfg.tag = this.href ? 'a' : 'button';
4755 cfg.html = this.html || '';
4756 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4758 cfg.href = this.href;
4761 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4764 // menu .. should add dropdown-menu class - so no need for carat..
4766 if (this.badge !== '') {
4768 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4773 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4777 href : this.href || "#",
4778 html: this.html || ''
4781 if (this.tagtype == 'a') {
4782 cfg.cn[0].cls = 'nav-link';
4785 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4788 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4790 if(this.glyphicon) {
4791 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4796 cfg.cn[0].html += " <span class='caret'></span>";
4800 if (this.badge !== '') {
4802 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4810 onRender : function(ct, position)
4812 // Roo.log("Call onRender: " + this.xtype);
4813 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4817 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4818 this.navLink = this.el.select('.nav-link',true).first();
4823 initEvents: function()
4825 if (typeof (this.menu) != 'undefined') {
4826 this.menu.parentType = this.xtype;
4827 this.menu.triggerEl = this.el;
4828 this.menu = this.addxtype(Roo.apply({}, this.menu));
4831 this.el.select('a',true).on('click', this.onClick, this);
4833 if(this.tagtype == 'span'){
4834 this.el.select('span',true).on('click', this.onClick, this);
4837 // at this point parent should be available..
4838 this.parent().register(this);
4841 onClick : function(e)
4843 if (e.getTarget('.dropdown-menu-item')) {
4844 // did you click on a menu itemm.... - then don't trigger onclick..
4849 this.preventDefault ||
4852 Roo.log("NavItem - prevent Default?");
4856 if (this.disabled) {
4860 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4861 if (tg && tg.transition) {
4862 Roo.log("waiting for the transitionend");
4868 //Roo.log("fire event clicked");
4869 if(this.fireEvent('click', this, e) === false){
4873 if(this.tagtype == 'span'){
4877 //Roo.log(this.href);
4878 var ael = this.el.select('a',true).first();
4881 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4882 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4883 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4884 return; // ignore... - it's a 'hash' to another page.
4886 Roo.log("NavItem - prevent Default?");
4888 this.scrollToElement(e);
4892 var p = this.parent();
4894 if (['tabs','pills'].indexOf(p.type)!==-1) {
4895 if (typeof(p.setActiveItem) !== 'undefined') {
4896 p.setActiveItem(this);
4900 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4901 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4902 // remove the collapsed menu expand...
4903 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
4907 isActive: function () {
4910 setActive : function(state, fire, is_was_active)
4912 if (this.active && !state && this.navId) {
4913 this.was_active = true;
4914 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4916 nv.clearWasActive(this);
4920 this.active = state;
4923 this.el.removeClass('active');
4924 this.navLink ? this.navLink.removeClass('active') : false;
4925 } else if (!this.el.hasClass('active')) {
4927 this.el.addClass('active');
4928 if (Roo.bootstrap.version == 4 && this.navLink ) {
4929 this.navLink.addClass('active');
4934 this.fireEvent('changed', this, state);
4937 // show a panel if it's registered and related..
4939 if (!this.navId || !this.tabId || !state || is_was_active) {
4943 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4947 var pan = tg.getPanelByName(this.tabId);
4951 // if we can not flip to new panel - go back to old nav highlight..
4952 if (false == tg.showPanel(pan)) {
4953 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4955 var onav = nv.getWasActive();
4957 onav.setActive(true, false, true);
4966 // this should not be here...
4967 setDisabled : function(state)
4969 this.disabled = state;
4971 this.el.removeClass('disabled');
4972 } else if (!this.el.hasClass('disabled')) {
4973 this.el.addClass('disabled');
4979 * Fetch the element to display the tooltip on.
4980 * @return {Roo.Element} defaults to this.el
4982 tooltipEl : function()
4984 return this.el.select('' + this.tagtype + '', true).first();
4987 scrollToElement : function(e)
4989 var c = document.body;
4992 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4994 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4995 c = document.documentElement;
4998 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
5004 var o = target.calcOffsetsTo(c);
5011 this.fireEvent('scrollto', this, options, e);
5013 Roo.get(c).scrollTo('top', options.value, true);
5026 * <span> icon </span>
5027 * <span> text </span>
5028 * <span>badge </span>
5032 * @class Roo.bootstrap.NavSidebarItem
5033 * @extends Roo.bootstrap.NavItem
5034 * Bootstrap Navbar.NavSidebarItem class
5035 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5036 * {Boolean} open is the menu open
5037 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5038 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5039 * {String} buttonSize (sm|md|lg)the extra classes for the button
5040 * {Boolean} showArrow show arrow next to the text (default true)
5042 * Create a new Navbar Button
5043 * @param {Object} config The config object
5045 Roo.bootstrap.NavSidebarItem = function(config){
5046 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5051 * The raw click event for the entire grid.
5052 * @param {Roo.EventObject} e
5057 * Fires when the active item active state changes
5058 * @param {Roo.bootstrap.NavSidebarItem} this
5059 * @param {boolean} state the new state
5067 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5069 badgeWeight : 'default',
5075 buttonWeight : 'default',
5081 getAutoCreate : function(){
5086 href : this.href || '#',
5092 if(this.buttonView){
5095 href : this.href || '#',
5096 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5109 cfg.cls += ' active';
5112 if (this.disabled) {
5113 cfg.cls += ' disabled';
5116 cfg.cls += ' open x-open';
5119 if (this.glyphicon || this.icon) {
5120 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5121 a.cn.push({ tag : 'i', cls : c }) ;
5124 if(!this.buttonView){
5127 html : this.html || ''
5134 if (this.badge !== '') {
5135 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5141 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5144 a.cls += ' dropdown-toggle treeview' ;
5150 initEvents : function()
5152 if (typeof (this.menu) != 'undefined') {
5153 this.menu.parentType = this.xtype;
5154 this.menu.triggerEl = this.el;
5155 this.menu = this.addxtype(Roo.apply({}, this.menu));
5158 this.el.on('click', this.onClick, this);
5160 if(this.badge !== ''){
5161 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5166 onClick : function(e)
5173 if(this.preventDefault){
5177 this.fireEvent('click', this, e);
5180 disable : function()
5182 this.setDisabled(true);
5187 this.setDisabled(false);
5190 setDisabled : function(state)
5192 if(this.disabled == state){
5196 this.disabled = state;
5199 this.el.addClass('disabled');
5203 this.el.removeClass('disabled');
5208 setActive : function(state)
5210 if(this.active == state){
5214 this.active = state;
5217 this.el.addClass('active');
5221 this.el.removeClass('active');
5226 isActive: function ()
5231 setBadge : function(str)
5237 this.badgeEl.dom.innerHTML = str;
5254 * @class Roo.bootstrap.Row
5255 * @extends Roo.bootstrap.Component
5256 * Bootstrap Row class (contains columns...)
5260 * @param {Object} config The config object
5263 Roo.bootstrap.Row = function(config){
5264 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5267 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5269 getAutoCreate : function(){
5288 * @class Roo.bootstrap.Element
5289 * @extends Roo.bootstrap.Component
5290 * Bootstrap Element class
5291 * @cfg {String} html contents of the element
5292 * @cfg {String} tag tag of the element
5293 * @cfg {String} cls class of the element
5294 * @cfg {Boolean} preventDefault (true|false) default false
5295 * @cfg {Boolean} clickable (true|false) default false
5298 * Create a new Element
5299 * @param {Object} config The config object
5302 Roo.bootstrap.Element = function(config){
5303 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5309 * When a element is chick
5310 * @param {Roo.bootstrap.Element} this
5311 * @param {Roo.EventObject} e
5317 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5322 preventDefault: false,
5325 getAutoCreate : function(){
5329 // cls: this.cls, double assign in parent class Component.js :: onRender
5336 initEvents: function()
5338 Roo.bootstrap.Element.superclass.initEvents.call(this);
5341 this.el.on('click', this.onClick, this);
5346 onClick : function(e)
5348 if(this.preventDefault){
5352 this.fireEvent('click', this, e);
5355 getValue : function()
5357 return this.el.dom.innerHTML;
5360 setValue : function(value)
5362 this.el.dom.innerHTML = value;
5377 * @class Roo.bootstrap.Pagination
5378 * @extends Roo.bootstrap.Component
5379 * Bootstrap Pagination class
5380 * @cfg {String} size xs | sm | md | lg
5381 * @cfg {Boolean} inverse false | true
5384 * Create a new Pagination
5385 * @param {Object} config The config object
5388 Roo.bootstrap.Pagination = function(config){
5389 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5392 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5398 getAutoCreate : function(){
5404 cfg.cls += ' inverse';
5410 cfg.cls += " " + this.cls;
5428 * @class Roo.bootstrap.PaginationItem
5429 * @extends Roo.bootstrap.Component
5430 * Bootstrap PaginationItem class
5431 * @cfg {String} html text
5432 * @cfg {String} href the link
5433 * @cfg {Boolean} preventDefault (true | false) default true
5434 * @cfg {Boolean} active (true | false) default false
5435 * @cfg {Boolean} disabled default false
5439 * Create a new PaginationItem
5440 * @param {Object} config The config object
5444 Roo.bootstrap.PaginationItem = function(config){
5445 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5450 * The raw click event for the entire grid.
5451 * @param {Roo.EventObject} e
5457 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5461 preventDefault: true,
5466 getAutoCreate : function(){
5472 href : this.href ? this.href : '#',
5473 html : this.html ? this.html : ''
5483 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5487 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5493 initEvents: function() {
5495 this.el.on('click', this.onClick, this);
5498 onClick : function(e)
5500 Roo.log('PaginationItem on click ');
5501 if(this.preventDefault){
5509 this.fireEvent('click', this, e);
5525 * @class Roo.bootstrap.Slider
5526 * @extends Roo.bootstrap.Component
5527 * Bootstrap Slider class
5530 * Create a new Slider
5531 * @param {Object} config The config object
5534 Roo.bootstrap.Slider = function(config){
5535 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5538 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5540 getAutoCreate : function(){
5544 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5548 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5560 * Ext JS Library 1.1.1
5561 * Copyright(c) 2006-2007, Ext JS, LLC.
5563 * Originally Released Under LGPL - original licence link has changed is not relivant.
5566 * <script type="text/javascript">
5571 * @class Roo.grid.ColumnModel
5572 * @extends Roo.util.Observable
5573 * This is the default implementation of a ColumnModel used by the Grid. It defines
5574 * the columns in the grid.
5577 var colModel = new Roo.grid.ColumnModel([
5578 {header: "Ticker", width: 60, sortable: true, locked: true},
5579 {header: "Company Name", width: 150, sortable: true},
5580 {header: "Market Cap.", width: 100, sortable: true},
5581 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5582 {header: "Employees", width: 100, sortable: true, resizable: false}
5587 * The config options listed for this class are options which may appear in each
5588 * individual column definition.
5589 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5591 * @param {Object} config An Array of column config objects. See this class's
5592 * config objects for details.
5594 Roo.grid.ColumnModel = function(config){
5596 * The config passed into the constructor
5598 this.config = config;
5601 // if no id, create one
5602 // if the column does not have a dataIndex mapping,
5603 // map it to the order it is in the config
5604 for(var i = 0, len = config.length; i < len; i++){
5606 if(typeof c.dataIndex == "undefined"){
5609 if(typeof c.renderer == "string"){
5610 c.renderer = Roo.util.Format[c.renderer];
5612 if(typeof c.id == "undefined"){
5615 if(c.editor && c.editor.xtype){
5616 c.editor = Roo.factory(c.editor, Roo.grid);
5618 if(c.editor && c.editor.isFormField){
5619 c.editor = new Roo.grid.GridEditor(c.editor);
5621 this.lookup[c.id] = c;
5625 * The width of columns which have no width specified (defaults to 100)
5628 this.defaultWidth = 100;
5631 * Default sortable of columns which have no sortable specified (defaults to false)
5634 this.defaultSortable = false;
5638 * @event widthchange
5639 * Fires when the width of a column changes.
5640 * @param {ColumnModel} this
5641 * @param {Number} columnIndex The column index
5642 * @param {Number} newWidth The new width
5644 "widthchange": true,
5646 * @event headerchange
5647 * Fires when the text of a header changes.
5648 * @param {ColumnModel} this
5649 * @param {Number} columnIndex The column index
5650 * @param {Number} newText The new header text
5652 "headerchange": true,
5654 * @event hiddenchange
5655 * Fires when a column is hidden or "unhidden".
5656 * @param {ColumnModel} this
5657 * @param {Number} columnIndex The column index
5658 * @param {Boolean} hidden true if hidden, false otherwise
5660 "hiddenchange": true,
5662 * @event columnmoved
5663 * Fires when a column is moved.
5664 * @param {ColumnModel} this
5665 * @param {Number} oldIndex
5666 * @param {Number} newIndex
5668 "columnmoved" : true,
5670 * @event columlockchange
5671 * Fires when a column's locked state is changed
5672 * @param {ColumnModel} this
5673 * @param {Number} colIndex
5674 * @param {Boolean} locked true if locked
5676 "columnlockchange" : true
5678 Roo.grid.ColumnModel.superclass.constructor.call(this);
5680 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5682 * @cfg {String} header The header text to display in the Grid view.
5685 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5686 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5687 * specified, the column's index is used as an index into the Record's data Array.
5690 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5691 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5694 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5695 * Defaults to the value of the {@link #defaultSortable} property.
5696 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5699 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5702 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5705 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5708 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5711 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5712 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5713 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5714 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5717 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5720 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5723 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5726 * @cfg {String} cursor (Optional)
5729 * @cfg {String} tooltip (Optional)
5732 * @cfg {Number} xs (Optional)
5735 * @cfg {Number} sm (Optional)
5738 * @cfg {Number} md (Optional)
5741 * @cfg {Number} lg (Optional)
5744 * Returns the id of the column at the specified index.
5745 * @param {Number} index The column index
5746 * @return {String} the id
5748 getColumnId : function(index){
5749 return this.config[index].id;
5753 * Returns the column for a specified id.
5754 * @param {String} id The column id
5755 * @return {Object} the column
5757 getColumnById : function(id){
5758 return this.lookup[id];
5763 * Returns the column for a specified dataIndex.
5764 * @param {String} dataIndex The column dataIndex
5765 * @return {Object|Boolean} the column or false if not found
5767 getColumnByDataIndex: function(dataIndex){
5768 var index = this.findColumnIndex(dataIndex);
5769 return index > -1 ? this.config[index] : false;
5773 * Returns the index for a specified column id.
5774 * @param {String} id The column id
5775 * @return {Number} the index, or -1 if not found
5777 getIndexById : function(id){
5778 for(var i = 0, len = this.config.length; i < len; i++){
5779 if(this.config[i].id == id){
5787 * Returns the index for a specified column dataIndex.
5788 * @param {String} dataIndex The column dataIndex
5789 * @return {Number} the index, or -1 if not found
5792 findColumnIndex : function(dataIndex){
5793 for(var i = 0, len = this.config.length; i < len; i++){
5794 if(this.config[i].dataIndex == dataIndex){
5802 moveColumn : function(oldIndex, newIndex){
5803 var c = this.config[oldIndex];
5804 this.config.splice(oldIndex, 1);
5805 this.config.splice(newIndex, 0, c);
5806 this.dataMap = null;
5807 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5810 isLocked : function(colIndex){
5811 return this.config[colIndex].locked === true;
5814 setLocked : function(colIndex, value, suppressEvent){
5815 if(this.isLocked(colIndex) == value){
5818 this.config[colIndex].locked = value;
5820 this.fireEvent("columnlockchange", this, colIndex, value);
5824 getTotalLockedWidth : function(){
5826 for(var i = 0; i < this.config.length; i++){
5827 if(this.isLocked(i) && !this.isHidden(i)){
5828 this.totalWidth += this.getColumnWidth(i);
5834 getLockedCount : function(){
5835 for(var i = 0, len = this.config.length; i < len; i++){
5836 if(!this.isLocked(i)){
5841 return this.config.length;
5845 * Returns the number of columns.
5848 getColumnCount : function(visibleOnly){
5849 if(visibleOnly === true){
5851 for(var i = 0, len = this.config.length; i < len; i++){
5852 if(!this.isHidden(i)){
5858 return this.config.length;
5862 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5863 * @param {Function} fn
5864 * @param {Object} scope (optional)
5865 * @return {Array} result
5867 getColumnsBy : function(fn, scope){
5869 for(var i = 0, len = this.config.length; i < len; i++){
5870 var c = this.config[i];
5871 if(fn.call(scope||this, c, i) === true){
5879 * Returns true if the specified column is sortable.
5880 * @param {Number} col The column index
5883 isSortable : function(col){
5884 if(typeof this.config[col].sortable == "undefined"){
5885 return this.defaultSortable;
5887 return this.config[col].sortable;
5891 * Returns the rendering (formatting) function defined for the column.
5892 * @param {Number} col The column index.
5893 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5895 getRenderer : function(col){
5896 if(!this.config[col].renderer){
5897 return Roo.grid.ColumnModel.defaultRenderer;
5899 return this.config[col].renderer;
5903 * Sets the rendering (formatting) function for a column.
5904 * @param {Number} col The column index
5905 * @param {Function} fn The function to use to process the cell's raw data
5906 * to return HTML markup for the grid view. The render function is called with
5907 * the following parameters:<ul>
5908 * <li>Data value.</li>
5909 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5910 * <li>css A CSS style string to apply to the table cell.</li>
5911 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5912 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5913 * <li>Row index</li>
5914 * <li>Column index</li>
5915 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5917 setRenderer : function(col, fn){
5918 this.config[col].renderer = fn;
5922 * Returns the width for the specified column.
5923 * @param {Number} col The column index
5926 getColumnWidth : function(col){
5927 return this.config[col].width * 1 || this.defaultWidth;
5931 * Sets the width for a column.
5932 * @param {Number} col The column index
5933 * @param {Number} width The new width
5935 setColumnWidth : function(col, width, suppressEvent){
5936 this.config[col].width = width;
5937 this.totalWidth = null;
5939 this.fireEvent("widthchange", this, col, width);
5944 * Returns the total width of all columns.
5945 * @param {Boolean} includeHidden True to include hidden column widths
5948 getTotalWidth : function(includeHidden){
5949 if(!this.totalWidth){
5950 this.totalWidth = 0;
5951 for(var i = 0, len = this.config.length; i < len; i++){
5952 if(includeHidden || !this.isHidden(i)){
5953 this.totalWidth += this.getColumnWidth(i);
5957 return this.totalWidth;
5961 * Returns the header for the specified column.
5962 * @param {Number} col The column index
5965 getColumnHeader : function(col){
5966 return this.config[col].header;
5970 * Sets the header for a column.
5971 * @param {Number} col The column index
5972 * @param {String} header The new header
5974 setColumnHeader : function(col, header){
5975 this.config[col].header = header;
5976 this.fireEvent("headerchange", this, col, header);
5980 * Returns the tooltip for the specified column.
5981 * @param {Number} col The column index
5984 getColumnTooltip : function(col){
5985 return this.config[col].tooltip;
5988 * Sets the tooltip for a column.
5989 * @param {Number} col The column index
5990 * @param {String} tooltip The new tooltip
5992 setColumnTooltip : function(col, tooltip){
5993 this.config[col].tooltip = tooltip;
5997 * Returns the dataIndex for the specified column.
5998 * @param {Number} col The column index
6001 getDataIndex : function(col){
6002 return this.config[col].dataIndex;
6006 * Sets the dataIndex for a column.
6007 * @param {Number} col The column index
6008 * @param {Number} dataIndex The new dataIndex
6010 setDataIndex : function(col, dataIndex){
6011 this.config[col].dataIndex = dataIndex;
6017 * Returns true if the cell is editable.
6018 * @param {Number} colIndex The column index
6019 * @param {Number} rowIndex The row index - this is nto actually used..?
6022 isCellEditable : function(colIndex, rowIndex){
6023 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6027 * Returns the editor defined for the cell/column.
6028 * return false or null to disable editing.
6029 * @param {Number} colIndex The column index
6030 * @param {Number} rowIndex The row index
6033 getCellEditor : function(colIndex, rowIndex){
6034 return this.config[colIndex].editor;
6038 * Sets if a column is editable.
6039 * @param {Number} col The column index
6040 * @param {Boolean} editable True if the column is editable
6042 setEditable : function(col, editable){
6043 this.config[col].editable = editable;
6048 * Returns true if the column is hidden.
6049 * @param {Number} colIndex The column index
6052 isHidden : function(colIndex){
6053 return this.config[colIndex].hidden;
6058 * Returns true if the column width cannot be changed
6060 isFixed : function(colIndex){
6061 return this.config[colIndex].fixed;
6065 * Returns true if the column can be resized
6068 isResizable : function(colIndex){
6069 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6072 * Sets if a column is hidden.
6073 * @param {Number} colIndex The column index
6074 * @param {Boolean} hidden True if the column is hidden
6076 setHidden : function(colIndex, hidden){
6077 this.config[colIndex].hidden = hidden;
6078 this.totalWidth = null;
6079 this.fireEvent("hiddenchange", this, colIndex, hidden);
6083 * Sets the editor for a column.
6084 * @param {Number} col The column index
6085 * @param {Object} editor The editor object
6087 setEditor : function(col, editor){
6088 this.config[col].editor = editor;
6092 Roo.grid.ColumnModel.defaultRenderer = function(value)
6094 if(typeof value == "object") {
6097 if(typeof value == "string" && value.length < 1){
6101 return String.format("{0}", value);
6104 // Alias for backwards compatibility
6105 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6108 * Ext JS Library 1.1.1
6109 * Copyright(c) 2006-2007, Ext JS, LLC.
6111 * Originally Released Under LGPL - original licence link has changed is not relivant.
6114 * <script type="text/javascript">
6118 * @class Roo.LoadMask
6119 * A simple utility class for generically masking elements while loading data. If the element being masked has
6120 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6121 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6122 * element's UpdateManager load indicator and will be destroyed after the initial load.
6124 * Create a new LoadMask
6125 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6126 * @param {Object} config The config object
6128 Roo.LoadMask = function(el, config){
6129 this.el = Roo.get(el);
6130 Roo.apply(this, config);
6132 this.store.on('beforeload', this.onBeforeLoad, this);
6133 this.store.on('load', this.onLoad, this);
6134 this.store.on('loadexception', this.onLoadException, this);
6135 this.removeMask = false;
6137 var um = this.el.getUpdateManager();
6138 um.showLoadIndicator = false; // disable the default indicator
6139 um.on('beforeupdate', this.onBeforeLoad, this);
6140 um.on('update', this.onLoad, this);
6141 um.on('failure', this.onLoad, this);
6142 this.removeMask = true;
6146 Roo.LoadMask.prototype = {
6148 * @cfg {Boolean} removeMask
6149 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6150 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6154 * The text to display in a centered loading message box (defaults to 'Loading...')
6158 * @cfg {String} msgCls
6159 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6161 msgCls : 'x-mask-loading',
6164 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6170 * Disables the mask to prevent it from being displayed
6172 disable : function(){
6173 this.disabled = true;
6177 * Enables the mask so that it can be displayed
6179 enable : function(){
6180 this.disabled = false;
6183 onLoadException : function()
6187 if (typeof(arguments[3]) != 'undefined') {
6188 Roo.MessageBox.alert("Error loading",arguments[3]);
6192 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6193 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6200 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6205 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6209 onBeforeLoad : function(){
6211 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6216 destroy : function(){
6218 this.store.un('beforeload', this.onBeforeLoad, this);
6219 this.store.un('load', this.onLoad, this);
6220 this.store.un('loadexception', this.onLoadException, this);
6222 var um = this.el.getUpdateManager();
6223 um.un('beforeupdate', this.onBeforeLoad, this);
6224 um.un('update', this.onLoad, this);
6225 um.un('failure', this.onLoad, this);
6236 * @class Roo.bootstrap.Table
6237 * @extends Roo.bootstrap.Component
6238 * Bootstrap Table class
6239 * @cfg {String} cls table class
6240 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6241 * @cfg {String} bgcolor Specifies the background color for a table
6242 * @cfg {Number} border Specifies whether the table cells should have borders or not
6243 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6244 * @cfg {Number} cellspacing Specifies the space between cells
6245 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6246 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6247 * @cfg {String} sortable Specifies that the table should be sortable
6248 * @cfg {String} summary Specifies a summary of the content of a table
6249 * @cfg {Number} width Specifies the width of a table
6250 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6252 * @cfg {boolean} striped Should the rows be alternative striped
6253 * @cfg {boolean} bordered Add borders to the table
6254 * @cfg {boolean} hover Add hover highlighting
6255 * @cfg {boolean} condensed Format condensed
6256 * @cfg {boolean} responsive Format condensed
6257 * @cfg {Boolean} loadMask (true|false) default false
6258 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6259 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6260 * @cfg {Boolean} rowSelection (true|false) default false
6261 * @cfg {Boolean} cellSelection (true|false) default false
6262 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6263 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6264 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6265 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6269 * Create a new Table
6270 * @param {Object} config The config object
6273 Roo.bootstrap.Table = function(config){
6274 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6279 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6280 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6281 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6282 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6284 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6286 this.sm.grid = this;
6287 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6288 this.sm = this.selModel;
6289 this.sm.xmodule = this.xmodule || false;
6292 if (this.cm && typeof(this.cm.config) == 'undefined') {
6293 this.colModel = new Roo.grid.ColumnModel(this.cm);
6294 this.cm = this.colModel;
6295 this.cm.xmodule = this.xmodule || false;
6298 this.store= Roo.factory(this.store, Roo.data);
6299 this.ds = this.store;
6300 this.ds.xmodule = this.xmodule || false;
6303 if (this.footer && this.store) {
6304 this.footer.dataSource = this.ds;
6305 this.footer = Roo.factory(this.footer);
6312 * Fires when a cell is clicked
6313 * @param {Roo.bootstrap.Table} this
6314 * @param {Roo.Element} el
6315 * @param {Number} rowIndex
6316 * @param {Number} columnIndex
6317 * @param {Roo.EventObject} e
6321 * @event celldblclick
6322 * Fires when a cell is double clicked
6323 * @param {Roo.bootstrap.Table} this
6324 * @param {Roo.Element} el
6325 * @param {Number} rowIndex
6326 * @param {Number} columnIndex
6327 * @param {Roo.EventObject} e
6329 "celldblclick" : true,
6332 * Fires when a row is clicked
6333 * @param {Roo.bootstrap.Table} this
6334 * @param {Roo.Element} el
6335 * @param {Number} rowIndex
6336 * @param {Roo.EventObject} e
6340 * @event rowdblclick
6341 * Fires when a row is double clicked
6342 * @param {Roo.bootstrap.Table} this
6343 * @param {Roo.Element} el
6344 * @param {Number} rowIndex
6345 * @param {Roo.EventObject} e
6347 "rowdblclick" : true,
6350 * Fires when a mouseover occur
6351 * @param {Roo.bootstrap.Table} this
6352 * @param {Roo.Element} el
6353 * @param {Number} rowIndex
6354 * @param {Number} columnIndex
6355 * @param {Roo.EventObject} e
6360 * Fires when a mouseout occur
6361 * @param {Roo.bootstrap.Table} this
6362 * @param {Roo.Element} el
6363 * @param {Number} rowIndex
6364 * @param {Number} columnIndex
6365 * @param {Roo.EventObject} e
6370 * Fires when a row is rendered, so you can change add a style to it.
6371 * @param {Roo.bootstrap.Table} this
6372 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6376 * @event rowsrendered
6377 * Fires when all the rows have been rendered
6378 * @param {Roo.bootstrap.Table} this
6380 'rowsrendered' : true,
6382 * @event contextmenu
6383 * The raw contextmenu event for the entire grid.
6384 * @param {Roo.EventObject} e
6386 "contextmenu" : true,
6388 * @event rowcontextmenu
6389 * Fires when a row is right clicked
6390 * @param {Roo.bootstrap.Table} this
6391 * @param {Number} rowIndex
6392 * @param {Roo.EventObject} e
6394 "rowcontextmenu" : true,
6396 * @event cellcontextmenu
6397 * Fires when a cell is right clicked
6398 * @param {Roo.bootstrap.Table} this
6399 * @param {Number} rowIndex
6400 * @param {Number} cellIndex
6401 * @param {Roo.EventObject} e
6403 "cellcontextmenu" : true,
6405 * @event headercontextmenu
6406 * Fires when a header is right clicked
6407 * @param {Roo.bootstrap.Table} this
6408 * @param {Number} columnIndex
6409 * @param {Roo.EventObject} e
6411 "headercontextmenu" : true
6415 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6441 rowSelection : false,
6442 cellSelection : false,
6445 // Roo.Element - the tbody
6447 // Roo.Element - thead element
6450 container: false, // used by gridpanel...
6456 auto_hide_footer : false,
6458 getAutoCreate : function()
6460 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6467 if (this.scrollBody) {
6468 cfg.cls += ' table-body-fixed';
6471 cfg.cls += ' table-striped';
6475 cfg.cls += ' table-hover';
6477 if (this.bordered) {
6478 cfg.cls += ' table-bordered';
6480 if (this.condensed) {
6481 cfg.cls += ' table-condensed';
6483 if (this.responsive) {
6484 cfg.cls += ' table-responsive';
6488 cfg.cls+= ' ' +this.cls;
6491 // this lot should be simplifed...
6504 ].forEach(function(k) {
6512 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6515 if(this.store || this.cm){
6516 if(this.headerShow){
6517 cfg.cn.push(this.renderHeader());
6520 cfg.cn.push(this.renderBody());
6522 if(this.footerShow){
6523 cfg.cn.push(this.renderFooter());
6525 // where does this come from?
6526 //cfg.cls+= ' TableGrid';
6529 return { cn : [ cfg ] };
6532 initEvents : function()
6534 if(!this.store || !this.cm){
6537 if (this.selModel) {
6538 this.selModel.initEvents();
6542 //Roo.log('initEvents with ds!!!!');
6544 this.mainBody = this.el.select('tbody', true).first();
6545 this.mainHead = this.el.select('thead', true).first();
6546 this.mainFoot = this.el.select('tfoot', true).first();
6552 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6553 e.on('click', _this.sort, _this);
6556 this.mainBody.on("click", this.onClick, this);
6557 this.mainBody.on("dblclick", this.onDblClick, this);
6559 // why is this done????? = it breaks dialogs??
6560 //this.parent().el.setStyle('position', 'relative');
6564 this.footer.parentId = this.id;
6565 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6568 this.el.select('tfoot tr td').first().addClass('hide');
6573 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6576 this.store.on('load', this.onLoad, this);
6577 this.store.on('beforeload', this.onBeforeLoad, this);
6578 this.store.on('update', this.onUpdate, this);
6579 this.store.on('add', this.onAdd, this);
6580 this.store.on("clear", this.clear, this);
6582 this.el.on("contextmenu", this.onContextMenu, this);
6584 this.mainBody.on('scroll', this.onBodyScroll, this);
6586 this.cm.on("headerchange", this.onHeaderChange, this);
6588 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6592 onContextMenu : function(e, t)
6594 this.processEvent("contextmenu", e);
6597 processEvent : function(name, e)
6599 if (name != 'touchstart' ) {
6600 this.fireEvent(name, e);
6603 var t = e.getTarget();
6605 var cell = Roo.get(t);
6611 if(cell.findParent('tfoot', false, true)){
6615 if(cell.findParent('thead', false, true)){
6617 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6618 cell = Roo.get(t).findParent('th', false, true);
6620 Roo.log("failed to find th in thead?");
6621 Roo.log(e.getTarget());
6626 var cellIndex = cell.dom.cellIndex;
6628 var ename = name == 'touchstart' ? 'click' : name;
6629 this.fireEvent("header" + ename, this, cellIndex, e);
6634 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6635 cell = Roo.get(t).findParent('td', false, true);
6637 Roo.log("failed to find th in tbody?");
6638 Roo.log(e.getTarget());
6643 var row = cell.findParent('tr', false, true);
6644 var cellIndex = cell.dom.cellIndex;
6645 var rowIndex = row.dom.rowIndex - 1;
6649 this.fireEvent("row" + name, this, rowIndex, e);
6653 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6659 onMouseover : function(e, el)
6661 var cell = Roo.get(el);
6667 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6668 cell = cell.findParent('td', false, true);
6671 var row = cell.findParent('tr', false, true);
6672 var cellIndex = cell.dom.cellIndex;
6673 var rowIndex = row.dom.rowIndex - 1; // start from 0
6675 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6679 onMouseout : function(e, el)
6681 var cell = Roo.get(el);
6687 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6688 cell = cell.findParent('td', false, true);
6691 var row = cell.findParent('tr', false, true);
6692 var cellIndex = cell.dom.cellIndex;
6693 var rowIndex = row.dom.rowIndex - 1; // start from 0
6695 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6699 onClick : function(e, el)
6701 var cell = Roo.get(el);
6703 if(!cell || (!this.cellSelection && !this.rowSelection)){
6707 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6708 cell = cell.findParent('td', false, true);
6711 if(!cell || typeof(cell) == 'undefined'){
6715 var row = cell.findParent('tr', false, true);
6717 if(!row || typeof(row) == 'undefined'){
6721 var cellIndex = cell.dom.cellIndex;
6722 var rowIndex = this.getRowIndex(row);
6724 // why??? - should these not be based on SelectionModel?
6725 if(this.cellSelection){
6726 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6729 if(this.rowSelection){
6730 this.fireEvent('rowclick', this, row, rowIndex, e);
6736 onDblClick : function(e,el)
6738 var cell = Roo.get(el);
6740 if(!cell || (!this.cellSelection && !this.rowSelection)){
6744 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6745 cell = cell.findParent('td', false, true);
6748 if(!cell || typeof(cell) == 'undefined'){
6752 var row = cell.findParent('tr', false, true);
6754 if(!row || typeof(row) == 'undefined'){
6758 var cellIndex = cell.dom.cellIndex;
6759 var rowIndex = this.getRowIndex(row);
6761 if(this.cellSelection){
6762 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6765 if(this.rowSelection){
6766 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6770 sort : function(e,el)
6772 var col = Roo.get(el);
6774 if(!col.hasClass('sortable')){
6778 var sort = col.attr('sort');
6781 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6785 this.store.sortInfo = {field : sort, direction : dir};
6788 Roo.log("calling footer first");
6789 this.footer.onClick('first');
6792 this.store.load({ params : { start : 0 } });
6796 renderHeader : function()
6804 this.totalWidth = 0;
6806 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6808 var config = cm.config[i];
6812 cls : 'x-hcol-' + i,
6814 html: cm.getColumnHeader(i)
6819 if(typeof(config.sortable) != 'undefined' && config.sortable){
6821 c.html = '<i class="glyphicon"></i>' + c.html;
6824 // could use BS4 hidden-..-down
6826 if(typeof(config.lgHeader) != 'undefined'){
6827 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
6830 if(typeof(config.mdHeader) != 'undefined'){
6831 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6834 if(typeof(config.smHeader) != 'undefined'){
6835 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6838 if(typeof(config.xsHeader) != 'undefined'){
6839 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6846 if(typeof(config.tooltip) != 'undefined'){
6847 c.tooltip = config.tooltip;
6850 if(typeof(config.colspan) != 'undefined'){
6851 c.colspan = config.colspan;
6854 if(typeof(config.hidden) != 'undefined' && config.hidden){
6855 c.style += ' display:none;';
6858 if(typeof(config.dataIndex) != 'undefined'){
6859 c.sort = config.dataIndex;
6864 if(typeof(config.align) != 'undefined' && config.align.length){
6865 c.style += ' text-align:' + config.align + ';';
6868 if(typeof(config.width) != 'undefined'){
6869 c.style += ' width:' + config.width + 'px;';
6870 this.totalWidth += config.width;
6872 this.totalWidth += 100; // assume minimum of 100 per column?
6875 if(typeof(config.cls) != 'undefined'){
6876 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6879 ['xs','sm','md','lg'].map(function(size){
6881 if(typeof(config[size]) == 'undefined'){
6885 if (!config[size]) { // 0 = hidden
6886 // BS 4 '0' is treated as hide that column and below.
6887 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
6891 c.cls += ' col-' + size + '-' + config[size] + (
6892 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
6904 renderBody : function()
6914 colspan : this.cm.getColumnCount()
6924 renderFooter : function()
6934 colspan : this.cm.getColumnCount()
6948 // Roo.log('ds onload');
6953 var ds = this.store;
6955 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6956 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6957 if (_this.store.sortInfo) {
6959 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6960 e.select('i', true).addClass(['glyphicon-arrow-up']);
6963 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6964 e.select('i', true).addClass(['glyphicon-arrow-down']);
6969 var tbody = this.mainBody;
6971 if(ds.getCount() > 0){
6972 ds.data.each(function(d,rowIndex){
6973 var row = this.renderRow(cm, ds, rowIndex);
6975 tbody.createChild(row);
6979 if(row.cellObjects.length){
6980 Roo.each(row.cellObjects, function(r){
6981 _this.renderCellObject(r);
6988 var tfoot = this.el.select('tfoot', true).first();
6990 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6992 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6994 var total = this.ds.getTotalCount();
6996 if(this.footer.pageSize < total){
6997 this.mainFoot.show();
7001 Roo.each(this.el.select('tbody td', true).elements, function(e){
7002 e.on('mouseover', _this.onMouseover, _this);
7005 Roo.each(this.el.select('tbody td', true).elements, function(e){
7006 e.on('mouseout', _this.onMouseout, _this);
7008 this.fireEvent('rowsrendered', this);
7014 onUpdate : function(ds,record)
7016 this.refreshRow(record);
7020 onRemove : function(ds, record, index, isUpdate){
7021 if(isUpdate !== true){
7022 this.fireEvent("beforerowremoved", this, index, record);
7024 var bt = this.mainBody.dom;
7026 var rows = this.el.select('tbody > tr', true).elements;
7028 if(typeof(rows[index]) != 'undefined'){
7029 bt.removeChild(rows[index].dom);
7032 // if(bt.rows[index]){
7033 // bt.removeChild(bt.rows[index]);
7036 if(isUpdate !== true){
7037 //this.stripeRows(index);
7038 //this.syncRowHeights(index, index);
7040 this.fireEvent("rowremoved", this, index, record);
7044 onAdd : function(ds, records, rowIndex)
7046 //Roo.log('on Add called');
7047 // - note this does not handle multiple adding very well..
7048 var bt = this.mainBody.dom;
7049 for (var i =0 ; i < records.length;i++) {
7050 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7051 //Roo.log(records[i]);
7052 //Roo.log(this.store.getAt(rowIndex+i));
7053 this.insertRow(this.store, rowIndex + i, false);
7060 refreshRow : function(record){
7061 var ds = this.store, index;
7062 if(typeof record == 'number'){
7064 record = ds.getAt(index);
7066 index = ds.indexOf(record);
7068 this.insertRow(ds, index, true);
7070 this.onRemove(ds, record, index+1, true);
7072 //this.syncRowHeights(index, index);
7074 this.fireEvent("rowupdated", this, index, record);
7077 insertRow : function(dm, rowIndex, isUpdate){
7080 this.fireEvent("beforerowsinserted", this, rowIndex);
7082 //var s = this.getScrollState();
7083 var row = this.renderRow(this.cm, this.store, rowIndex);
7084 // insert before rowIndex..
7085 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7089 if(row.cellObjects.length){
7090 Roo.each(row.cellObjects, function(r){
7091 _this.renderCellObject(r);
7096 this.fireEvent("rowsinserted", this, rowIndex);
7097 //this.syncRowHeights(firstRow, lastRow);
7098 //this.stripeRows(firstRow);
7105 getRowDom : function(rowIndex)
7107 var rows = this.el.select('tbody > tr', true).elements;
7109 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7112 // returns the object tree for a tr..
7115 renderRow : function(cm, ds, rowIndex)
7117 var d = ds.getAt(rowIndex);
7121 cls : 'x-row-' + rowIndex,
7125 var cellObjects = [];
7127 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7128 var config = cm.config[i];
7130 var renderer = cm.getRenderer(i);
7134 if(typeof(renderer) !== 'undefined'){
7135 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7137 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7138 // and are rendered into the cells after the row is rendered - using the id for the element.
7140 if(typeof(value) === 'object'){
7150 rowIndex : rowIndex,
7155 this.fireEvent('rowclass', this, rowcfg);
7159 cls : rowcfg.rowClass + ' x-col-' + i,
7161 html: (typeof(value) === 'object') ? '' : value
7168 if(typeof(config.colspan) != 'undefined'){
7169 td.colspan = config.colspan;
7172 if(typeof(config.hidden) != 'undefined' && config.hidden){
7173 td.style += ' display:none;';
7176 if(typeof(config.align) != 'undefined' && config.align.length){
7177 td.style += ' text-align:' + config.align + ';';
7179 if(typeof(config.valign) != 'undefined' && config.valign.length){
7180 td.style += ' vertical-align:' + config.valign + ';';
7183 if(typeof(config.width) != 'undefined'){
7184 td.style += ' width:' + config.width + 'px;';
7187 if(typeof(config.cursor) != 'undefined'){
7188 td.style += ' cursor:' + config.cursor + ';';
7191 if(typeof(config.cls) != 'undefined'){
7192 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7195 ['xs','sm','md','lg'].map(function(size){
7197 if(typeof(config[size]) == 'undefined'){
7203 if (!config[size]) { // 0 = hidden
7204 // BS 4 '0' is treated as hide that column and below.
7205 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
7209 td.cls += ' col-' + size + '-' + config[size] + (
7210 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7220 row.cellObjects = cellObjects;
7228 onBeforeLoad : function()
7237 this.el.select('tbody', true).first().dom.innerHTML = '';
7240 * Show or hide a row.
7241 * @param {Number} rowIndex to show or hide
7242 * @param {Boolean} state hide
7244 setRowVisibility : function(rowIndex, state)
7246 var bt = this.mainBody.dom;
7248 var rows = this.el.select('tbody > tr', true).elements;
7250 if(typeof(rows[rowIndex]) == 'undefined'){
7253 rows[rowIndex].dom.style.display = state ? '' : 'none';
7257 getSelectionModel : function(){
7259 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7261 return this.selModel;
7264 * Render the Roo.bootstrap object from renderder
7266 renderCellObject : function(r)
7270 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7272 var t = r.cfg.render(r.container);
7275 Roo.each(r.cfg.cn, function(c){
7277 container: t.getChildContainer(),
7280 _this.renderCellObject(child);
7285 getRowIndex : function(row)
7289 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7300 * Returns the grid's underlying element = used by panel.Grid
7301 * @return {Element} The element
7303 getGridEl : function(){
7307 * Forces a resize - used by panel.Grid
7308 * @return {Element} The element
7310 autoSize : function()
7312 //var ctr = Roo.get(this.container.dom.parentElement);
7313 var ctr = Roo.get(this.el.dom);
7315 var thd = this.getGridEl().select('thead',true).first();
7316 var tbd = this.getGridEl().select('tbody', true).first();
7317 var tfd = this.getGridEl().select('tfoot', true).first();
7319 var cw = ctr.getWidth();
7323 tbd.setSize(ctr.getWidth(),
7324 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7326 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7329 cw = Math.max(cw, this.totalWidth);
7330 this.getGridEl().select('tr',true).setWidth(cw);
7331 // resize 'expandable coloumn?
7333 return; // we doe not have a view in this design..
7336 onBodyScroll: function()
7338 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7340 this.mainHead.setStyle({
7341 'position' : 'relative',
7342 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7348 var scrollHeight = this.mainBody.dom.scrollHeight;
7350 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7352 var height = this.mainBody.getHeight();
7354 if(scrollHeight - height == scrollTop) {
7356 var total = this.ds.getTotalCount();
7358 if(this.footer.cursor + this.footer.pageSize < total){
7360 this.footer.ds.load({
7362 start : this.footer.cursor + this.footer.pageSize,
7363 limit : this.footer.pageSize
7373 onHeaderChange : function()
7375 var header = this.renderHeader();
7376 var table = this.el.select('table', true).first();
7378 this.mainHead.remove();
7379 this.mainHead = table.createChild(header, this.mainBody, false);
7382 onHiddenChange : function(colModel, colIndex, hidden)
7384 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7385 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7387 this.CSS.updateRule(thSelector, "display", "");
7388 this.CSS.updateRule(tdSelector, "display", "");
7391 this.CSS.updateRule(thSelector, "display", "none");
7392 this.CSS.updateRule(tdSelector, "display", "none");
7395 this.onHeaderChange();
7399 setColumnWidth: function(col_index, width)
7401 // width = "md-2 xs-2..."
7402 if(!this.colModel.config[col_index]) {
7406 var w = width.split(" ");
7408 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7410 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7413 for(var j = 0; j < w.length; j++) {
7419 var size_cls = w[j].split("-");
7421 if(!Number.isInteger(size_cls[1] * 1)) {
7425 if(!this.colModel.config[col_index][size_cls[0]]) {
7429 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7433 h_row[0].classList.replace(
7434 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7435 "col-"+size_cls[0]+"-"+size_cls[1]
7438 for(var i = 0; i < rows.length; i++) {
7440 var size_cls = w[j].split("-");
7442 if(!Number.isInteger(size_cls[1] * 1)) {
7446 if(!this.colModel.config[col_index][size_cls[0]]) {
7450 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7454 rows[i].classList.replace(
7455 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7456 "col-"+size_cls[0]+"-"+size_cls[1]
7460 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7475 * @class Roo.bootstrap.TableCell
7476 * @extends Roo.bootstrap.Component
7477 * Bootstrap TableCell class
7478 * @cfg {String} html cell contain text
7479 * @cfg {String} cls cell class
7480 * @cfg {String} tag cell tag (td|th) default td
7481 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7482 * @cfg {String} align Aligns the content in a cell
7483 * @cfg {String} axis Categorizes cells
7484 * @cfg {String} bgcolor Specifies the background color of a cell
7485 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7486 * @cfg {Number} colspan Specifies the number of columns a cell should span
7487 * @cfg {String} headers Specifies one or more header cells a cell is related to
7488 * @cfg {Number} height Sets the height of a cell
7489 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7490 * @cfg {Number} rowspan Sets the number of rows a cell should span
7491 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7492 * @cfg {String} valign Vertical aligns the content in a cell
7493 * @cfg {Number} width Specifies the width of a cell
7496 * Create a new TableCell
7497 * @param {Object} config The config object
7500 Roo.bootstrap.TableCell = function(config){
7501 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7504 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7524 getAutoCreate : function(){
7525 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7545 cfg.align=this.align
7551 cfg.bgcolor=this.bgcolor
7554 cfg.charoff=this.charoff
7557 cfg.colspan=this.colspan
7560 cfg.headers=this.headers
7563 cfg.height=this.height
7566 cfg.nowrap=this.nowrap
7569 cfg.rowspan=this.rowspan
7572 cfg.scope=this.scope
7575 cfg.valign=this.valign
7578 cfg.width=this.width
7597 * @class Roo.bootstrap.TableRow
7598 * @extends Roo.bootstrap.Component
7599 * Bootstrap TableRow class
7600 * @cfg {String} cls row class
7601 * @cfg {String} align Aligns the content in a table row
7602 * @cfg {String} bgcolor Specifies a background color for a table row
7603 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7604 * @cfg {String} valign Vertical aligns the content in a table row
7607 * Create a new TableRow
7608 * @param {Object} config The config object
7611 Roo.bootstrap.TableRow = function(config){
7612 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7615 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7623 getAutoCreate : function(){
7624 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7634 cfg.align = this.align;
7637 cfg.bgcolor = this.bgcolor;
7640 cfg.charoff = this.charoff;
7643 cfg.valign = this.valign;
7661 * @class Roo.bootstrap.TableBody
7662 * @extends Roo.bootstrap.Component
7663 * Bootstrap TableBody class
7664 * @cfg {String} cls element class
7665 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7666 * @cfg {String} align Aligns the content inside the element
7667 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7668 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7671 * Create a new TableBody
7672 * @param {Object} config The config object
7675 Roo.bootstrap.TableBody = function(config){
7676 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7679 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7687 getAutoCreate : function(){
7688 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7702 cfg.align = this.align;
7705 cfg.charoff = this.charoff;
7708 cfg.valign = this.valign;
7715 // initEvents : function()
7722 // this.store = Roo.factory(this.store, Roo.data);
7723 // this.store.on('load', this.onLoad, this);
7725 // this.store.load();
7729 // onLoad: function ()
7731 // this.fireEvent('load', this);
7741 * Ext JS Library 1.1.1
7742 * Copyright(c) 2006-2007, Ext JS, LLC.
7744 * Originally Released Under LGPL - original licence link has changed is not relivant.
7747 * <script type="text/javascript">
7750 // as we use this in bootstrap.
7751 Roo.namespace('Roo.form');
7753 * @class Roo.form.Action
7754 * Internal Class used to handle form actions
7756 * @param {Roo.form.BasicForm} el The form element or its id
7757 * @param {Object} config Configuration options
7762 // define the action interface
7763 Roo.form.Action = function(form, options){
7765 this.options = options || {};
7768 * Client Validation Failed
7771 Roo.form.Action.CLIENT_INVALID = 'client';
7773 * Server Validation Failed
7776 Roo.form.Action.SERVER_INVALID = 'server';
7778 * Connect to Server Failed
7781 Roo.form.Action.CONNECT_FAILURE = 'connect';
7783 * Reading Data from Server Failed
7786 Roo.form.Action.LOAD_FAILURE = 'load';
7788 Roo.form.Action.prototype = {
7790 failureType : undefined,
7791 response : undefined,
7795 run : function(options){
7800 success : function(response){
7805 handleResponse : function(response){
7809 // default connection failure
7810 failure : function(response){
7812 this.response = response;
7813 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7814 this.form.afterAction(this, false);
7817 processResponse : function(response){
7818 this.response = response;
7819 if(!response.responseText){
7822 this.result = this.handleResponse(response);
7826 // utility functions used internally
7827 getUrl : function(appendParams){
7828 var url = this.options.url || this.form.url || this.form.el.dom.action;
7830 var p = this.getParams();
7832 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7838 getMethod : function(){
7839 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7842 getParams : function(){
7843 var bp = this.form.baseParams;
7844 var p = this.options.params;
7846 if(typeof p == "object"){
7847 p = Roo.urlEncode(Roo.applyIf(p, bp));
7848 }else if(typeof p == 'string' && bp){
7849 p += '&' + Roo.urlEncode(bp);
7852 p = Roo.urlEncode(bp);
7857 createCallback : function(){
7859 success: this.success,
7860 failure: this.failure,
7862 timeout: (this.form.timeout*1000),
7863 upload: this.form.fileUpload ? this.success : undefined
7868 Roo.form.Action.Submit = function(form, options){
7869 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7872 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7875 haveProgress : false,
7876 uploadComplete : false,
7878 // uploadProgress indicator.
7879 uploadProgress : function()
7881 if (!this.form.progressUrl) {
7885 if (!this.haveProgress) {
7886 Roo.MessageBox.progress("Uploading", "Uploading");
7888 if (this.uploadComplete) {
7889 Roo.MessageBox.hide();
7893 this.haveProgress = true;
7895 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7897 var c = new Roo.data.Connection();
7899 url : this.form.progressUrl,
7904 success : function(req){
7905 //console.log(data);
7909 rdata = Roo.decode(req.responseText)
7911 Roo.log("Invalid data from server..");
7915 if (!rdata || !rdata.success) {
7917 Roo.MessageBox.alert(Roo.encode(rdata));
7920 var data = rdata.data;
7922 if (this.uploadComplete) {
7923 Roo.MessageBox.hide();
7928 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7929 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7932 this.uploadProgress.defer(2000,this);
7935 failure: function(data) {
7936 Roo.log('progress url failed ');
7947 // run get Values on the form, so it syncs any secondary forms.
7948 this.form.getValues();
7950 var o = this.options;
7951 var method = this.getMethod();
7952 var isPost = method == 'POST';
7953 if(o.clientValidation === false || this.form.isValid()){
7955 if (this.form.progressUrl) {
7956 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7957 (new Date() * 1) + '' + Math.random());
7962 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7963 form:this.form.el.dom,
7964 url:this.getUrl(!isPost),
7966 params:isPost ? this.getParams() : null,
7967 isUpload: this.form.fileUpload,
7968 formData : this.form.formData
7971 this.uploadProgress();
7973 }else if (o.clientValidation !== false){ // client validation failed
7974 this.failureType = Roo.form.Action.CLIENT_INVALID;
7975 this.form.afterAction(this, false);
7979 success : function(response)
7981 this.uploadComplete= true;
7982 if (this.haveProgress) {
7983 Roo.MessageBox.hide();
7987 var result = this.processResponse(response);
7988 if(result === true || result.success){
7989 this.form.afterAction(this, true);
7993 this.form.markInvalid(result.errors);
7994 this.failureType = Roo.form.Action.SERVER_INVALID;
7996 this.form.afterAction(this, false);
7998 failure : function(response)
8000 this.uploadComplete= true;
8001 if (this.haveProgress) {
8002 Roo.MessageBox.hide();
8005 this.response = response;
8006 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8007 this.form.afterAction(this, false);
8010 handleResponse : function(response){
8011 if(this.form.errorReader){
8012 var rs = this.form.errorReader.read(response);
8015 for(var i = 0, len = rs.records.length; i < len; i++) {
8016 var r = rs.records[i];
8020 if(errors.length < 1){
8024 success : rs.success,
8030 ret = Roo.decode(response.responseText);
8034 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8044 Roo.form.Action.Load = function(form, options){
8045 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8046 this.reader = this.form.reader;
8049 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8054 Roo.Ajax.request(Roo.apply(
8055 this.createCallback(), {
8056 method:this.getMethod(),
8057 url:this.getUrl(false),
8058 params:this.getParams()
8062 success : function(response){
8064 var result = this.processResponse(response);
8065 if(result === true || !result.success || !result.data){
8066 this.failureType = Roo.form.Action.LOAD_FAILURE;
8067 this.form.afterAction(this, false);
8070 this.form.clearInvalid();
8071 this.form.setValues(result.data);
8072 this.form.afterAction(this, true);
8075 handleResponse : function(response){
8076 if(this.form.reader){
8077 var rs = this.form.reader.read(response);
8078 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8080 success : rs.success,
8084 return Roo.decode(response.responseText);
8088 Roo.form.Action.ACTION_TYPES = {
8089 'load' : Roo.form.Action.Load,
8090 'submit' : Roo.form.Action.Submit
8099 * @class Roo.bootstrap.Form
8100 * @extends Roo.bootstrap.Component
8101 * Bootstrap Form class
8102 * @cfg {String} method GET | POST (default POST)
8103 * @cfg {String} labelAlign top | left (default top)
8104 * @cfg {String} align left | right - for navbars
8105 * @cfg {Boolean} loadMask load mask when submit (default true)
8110 * @param {Object} config The config object
8114 Roo.bootstrap.Form = function(config){
8116 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8118 Roo.bootstrap.Form.popover.apply();
8122 * @event clientvalidation
8123 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8124 * @param {Form} this
8125 * @param {Boolean} valid true if the form has passed client-side validation
8127 clientvalidation: true,
8129 * @event beforeaction
8130 * Fires before any action is performed. Return false to cancel the action.
8131 * @param {Form} this
8132 * @param {Action} action The action to be performed
8136 * @event actionfailed
8137 * Fires when an action fails.
8138 * @param {Form} this
8139 * @param {Action} action The action that failed
8141 actionfailed : true,
8143 * @event actioncomplete
8144 * Fires when an action is completed.
8145 * @param {Form} this
8146 * @param {Action} action The action that completed
8148 actioncomplete : true
8152 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8155 * @cfg {String} method
8156 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8161 * The URL to use for form actions if one isn't supplied in the action options.
8164 * @cfg {Boolean} fileUpload
8165 * Set to true if this form is a file upload.
8169 * @cfg {Object} baseParams
8170 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8174 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8178 * @cfg {Sting} align (left|right) for navbar forms
8183 activeAction : null,
8186 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8187 * element by passing it or its id or mask the form itself by passing in true.
8190 waitMsgTarget : false,
8195 * @cfg {Boolean} errorMask (true|false) default false
8200 * @cfg {Number} maskOffset Default 100
8205 * @cfg {Boolean} maskBody
8209 getAutoCreate : function(){
8213 method : this.method || 'POST',
8214 id : this.id || Roo.id(),
8217 if (this.parent().xtype.match(/^Nav/)) {
8218 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8222 if (this.labelAlign == 'left' ) {
8223 cfg.cls += ' form-horizontal';
8229 initEvents : function()
8231 this.el.on('submit', this.onSubmit, this);
8232 // this was added as random key presses on the form where triggering form submit.
8233 this.el.on('keypress', function(e) {
8234 if (e.getCharCode() != 13) {
8237 // we might need to allow it for textareas.. and some other items.
8238 // check e.getTarget().
8240 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8244 Roo.log("keypress blocked");
8252 onSubmit : function(e){
8257 * Returns true if client-side validation on the form is successful.
8260 isValid : function(){
8261 var items = this.getItems();
8265 items.each(function(f){
8271 Roo.log('invalid field: ' + f.name);
8275 if(!target && f.el.isVisible(true)){
8281 if(this.errorMask && !valid){
8282 Roo.bootstrap.Form.popover.mask(this, target);
8289 * Returns true if any fields in this form have changed since their original load.
8292 isDirty : function(){
8294 var items = this.getItems();
8295 items.each(function(f){
8305 * Performs a predefined action (submit or load) or custom actions you define on this form.
8306 * @param {String} actionName The name of the action type
8307 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8308 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8309 * accept other config options):
8311 Property Type Description
8312 ---------------- --------------- ----------------------------------------------------------------------------------
8313 url String The url for the action (defaults to the form's url)
8314 method String The form method to use (defaults to the form's method, or POST if not defined)
8315 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8316 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8317 validate the form on the client (defaults to false)
8319 * @return {BasicForm} this
8321 doAction : function(action, options){
8322 if(typeof action == 'string'){
8323 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8325 if(this.fireEvent('beforeaction', this, action) !== false){
8326 this.beforeAction(action);
8327 action.run.defer(100, action);
8333 beforeAction : function(action){
8334 var o = action.options;
8339 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8341 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8344 // not really supported yet.. ??
8346 //if(this.waitMsgTarget === true){
8347 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8348 //}else if(this.waitMsgTarget){
8349 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8350 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8352 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8358 afterAction : function(action, success){
8359 this.activeAction = null;
8360 var o = action.options;
8365 Roo.get(document.body).unmask();
8371 //if(this.waitMsgTarget === true){
8372 // this.el.unmask();
8373 //}else if(this.waitMsgTarget){
8374 // this.waitMsgTarget.unmask();
8376 // Roo.MessageBox.updateProgress(1);
8377 // Roo.MessageBox.hide();
8384 Roo.callback(o.success, o.scope, [this, action]);
8385 this.fireEvent('actioncomplete', this, action);
8389 // failure condition..
8390 // we have a scenario where updates need confirming.
8391 // eg. if a locking scenario exists..
8392 // we look for { errors : { needs_confirm : true }} in the response.
8394 (typeof(action.result) != 'undefined') &&
8395 (typeof(action.result.errors) != 'undefined') &&
8396 (typeof(action.result.errors.needs_confirm) != 'undefined')
8399 Roo.log("not supported yet");
8402 Roo.MessageBox.confirm(
8403 "Change requires confirmation",
8404 action.result.errorMsg,
8409 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8419 Roo.callback(o.failure, o.scope, [this, action]);
8420 // show an error message if no failed handler is set..
8421 if (!this.hasListener('actionfailed')) {
8422 Roo.log("need to add dialog support");
8424 Roo.MessageBox.alert("Error",
8425 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8426 action.result.errorMsg :
8427 "Saving Failed, please check your entries or try again"
8432 this.fireEvent('actionfailed', this, action);
8437 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8438 * @param {String} id The value to search for
8441 findField : function(id){
8442 var items = this.getItems();
8443 var field = items.get(id);
8445 items.each(function(f){
8446 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8453 return field || null;
8456 * Mark fields in this form invalid in bulk.
8457 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8458 * @return {BasicForm} this
8460 markInvalid : function(errors){
8461 if(errors instanceof Array){
8462 for(var i = 0, len = errors.length; i < len; i++){
8463 var fieldError = errors[i];
8464 var f = this.findField(fieldError.id);
8466 f.markInvalid(fieldError.msg);
8472 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8473 field.markInvalid(errors[id]);
8477 //Roo.each(this.childForms || [], function (f) {
8478 // f.markInvalid(errors);
8485 * Set values for fields in this form in bulk.
8486 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8487 * @return {BasicForm} this
8489 setValues : function(values){
8490 if(values instanceof Array){ // array of objects
8491 for(var i = 0, len = values.length; i < len; i++){
8493 var f = this.findField(v.id);
8495 f.setValue(v.value);
8496 if(this.trackResetOnLoad){
8497 f.originalValue = f.getValue();
8501 }else{ // object hash
8504 if(typeof values[id] != 'function' && (field = this.findField(id))){
8506 if (field.setFromData &&
8508 field.displayField &&
8509 // combos' with local stores can
8510 // be queried via setValue()
8511 // to set their value..
8512 (field.store && !field.store.isLocal)
8516 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8517 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8518 field.setFromData(sd);
8520 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8522 field.setFromData(values);
8525 field.setValue(values[id]);
8529 if(this.trackResetOnLoad){
8530 field.originalValue = field.getValue();
8536 //Roo.each(this.childForms || [], function (f) {
8537 // f.setValues(values);
8544 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8545 * they are returned as an array.
8546 * @param {Boolean} asString
8549 getValues : function(asString){
8550 //if (this.childForms) {
8551 // copy values from the child forms
8552 // Roo.each(this.childForms, function (f) {
8553 // this.setValues(f.getValues());
8559 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8560 if(asString === true){
8563 return Roo.urlDecode(fs);
8567 * Returns the fields in this form as an object with key/value pairs.
8568 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8571 getFieldValues : function(with_hidden)
8573 var items = this.getItems();
8575 items.each(function(f){
8581 var v = f.getValue();
8583 if (f.inputType =='radio') {
8584 if (typeof(ret[f.getName()]) == 'undefined') {
8585 ret[f.getName()] = ''; // empty..
8588 if (!f.el.dom.checked) {
8596 if(f.xtype == 'MoneyField'){
8597 ret[f.currencyName] = f.getCurrency();
8600 // not sure if this supported any more..
8601 if ((typeof(v) == 'object') && f.getRawValue) {
8602 v = f.getRawValue() ; // dates..
8604 // combo boxes where name != hiddenName...
8605 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8606 ret[f.name] = f.getRawValue();
8608 ret[f.getName()] = v;
8615 * Clears all invalid messages in this form.
8616 * @return {BasicForm} this
8618 clearInvalid : function(){
8619 var items = this.getItems();
8621 items.each(function(f){
8630 * @return {BasicForm} this
8633 var items = this.getItems();
8634 items.each(function(f){
8638 Roo.each(this.childForms || [], function (f) {
8646 getItems : function()
8648 var r=new Roo.util.MixedCollection(false, function(o){
8649 return o.id || (o.id = Roo.id());
8651 var iter = function(el) {
8658 Roo.each(el.items,function(e) {
8667 hideFields : function(items)
8669 Roo.each(items, function(i){
8671 var f = this.findField(i);
8682 showFields : function(items)
8684 Roo.each(items, function(i){
8686 var f = this.findField(i);
8699 Roo.apply(Roo.bootstrap.Form, {
8726 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8727 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8728 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8729 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8732 this.maskEl.top.enableDisplayMode("block");
8733 this.maskEl.left.enableDisplayMode("block");
8734 this.maskEl.bottom.enableDisplayMode("block");
8735 this.maskEl.right.enableDisplayMode("block");
8737 this.toolTip = new Roo.bootstrap.Tooltip({
8738 cls : 'roo-form-error-popover',
8740 'left' : ['r-l', [-2,0], 'right'],
8741 'right' : ['l-r', [2,0], 'left'],
8742 'bottom' : ['tl-bl', [0,2], 'top'],
8743 'top' : [ 'bl-tl', [0,-2], 'bottom']
8747 this.toolTip.render(Roo.get(document.body));
8749 this.toolTip.el.enableDisplayMode("block");
8751 Roo.get(document.body).on('click', function(){
8755 Roo.get(document.body).on('touchstart', function(){
8759 this.isApplied = true
8762 mask : function(form, target)
8766 this.target = target;
8768 if(!this.form.errorMask || !target.el){
8772 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8774 Roo.log(scrollable);
8776 var ot = this.target.el.calcOffsetsTo(scrollable);
8778 var scrollTo = ot[1] - this.form.maskOffset;
8780 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8782 scrollable.scrollTo('top', scrollTo);
8784 var box = this.target.el.getBox();
8786 var zIndex = Roo.bootstrap.Modal.zIndex++;
8789 this.maskEl.top.setStyle('position', 'absolute');
8790 this.maskEl.top.setStyle('z-index', zIndex);
8791 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8792 this.maskEl.top.setLeft(0);
8793 this.maskEl.top.setTop(0);
8794 this.maskEl.top.show();
8796 this.maskEl.left.setStyle('position', 'absolute');
8797 this.maskEl.left.setStyle('z-index', zIndex);
8798 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8799 this.maskEl.left.setLeft(0);
8800 this.maskEl.left.setTop(box.y - this.padding);
8801 this.maskEl.left.show();
8803 this.maskEl.bottom.setStyle('position', 'absolute');
8804 this.maskEl.bottom.setStyle('z-index', zIndex);
8805 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8806 this.maskEl.bottom.setLeft(0);
8807 this.maskEl.bottom.setTop(box.bottom + this.padding);
8808 this.maskEl.bottom.show();
8810 this.maskEl.right.setStyle('position', 'absolute');
8811 this.maskEl.right.setStyle('z-index', zIndex);
8812 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8813 this.maskEl.right.setLeft(box.right + this.padding);
8814 this.maskEl.right.setTop(box.y - this.padding);
8815 this.maskEl.right.show();
8817 this.toolTip.bindEl = this.target.el;
8819 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8821 var tip = this.target.blankText;
8823 if(this.target.getValue() !== '' ) {
8825 if (this.target.invalidText.length) {
8826 tip = this.target.invalidText;
8827 } else if (this.target.regexText.length){
8828 tip = this.target.regexText;
8832 this.toolTip.show(tip);
8834 this.intervalID = window.setInterval(function() {
8835 Roo.bootstrap.Form.popover.unmask();
8838 window.onwheel = function(){ return false;};
8840 (function(){ this.isMasked = true; }).defer(500, this);
8846 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8850 this.maskEl.top.setStyle('position', 'absolute');
8851 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8852 this.maskEl.top.hide();
8854 this.maskEl.left.setStyle('position', 'absolute');
8855 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8856 this.maskEl.left.hide();
8858 this.maskEl.bottom.setStyle('position', 'absolute');
8859 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8860 this.maskEl.bottom.hide();
8862 this.maskEl.right.setStyle('position', 'absolute');
8863 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8864 this.maskEl.right.hide();
8866 this.toolTip.hide();
8868 this.toolTip.el.hide();
8870 window.onwheel = function(){ return true;};
8872 if(this.intervalID){
8873 window.clearInterval(this.intervalID);
8874 this.intervalID = false;
8877 this.isMasked = false;
8887 * Ext JS Library 1.1.1
8888 * Copyright(c) 2006-2007, Ext JS, LLC.
8890 * Originally Released Under LGPL - original licence link has changed is not relivant.
8893 * <script type="text/javascript">
8896 * @class Roo.form.VTypes
8897 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8900 Roo.form.VTypes = function(){
8901 // closure these in so they are only created once.
8902 var alpha = /^[a-zA-Z_]+$/;
8903 var alphanum = /^[a-zA-Z0-9_]+$/;
8904 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8905 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8907 // All these messages and functions are configurable
8910 * The function used to validate email addresses
8911 * @param {String} value The email address
8913 'email' : function(v){
8914 return email.test(v);
8917 * The error text to display when the email validation function returns false
8920 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8922 * The keystroke filter mask to be applied on email input
8925 'emailMask' : /[a-z0-9_\.\-@]/i,
8928 * The function used to validate URLs
8929 * @param {String} value The URL
8931 'url' : function(v){
8935 * The error text to display when the url validation function returns false
8938 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8941 * The function used to validate alpha values
8942 * @param {String} value The value
8944 'alpha' : function(v){
8945 return alpha.test(v);
8948 * The error text to display when the alpha validation function returns false
8951 'alphaText' : 'This field should only contain letters and _',
8953 * The keystroke filter mask to be applied on alpha input
8956 'alphaMask' : /[a-z_]/i,
8959 * The function used to validate alphanumeric values
8960 * @param {String} value The value
8962 'alphanum' : function(v){
8963 return alphanum.test(v);
8966 * The error text to display when the alphanumeric validation function returns false
8969 'alphanumText' : 'This field should only contain letters, numbers and _',
8971 * The keystroke filter mask to be applied on alphanumeric input
8974 'alphanumMask' : /[a-z0-9_]/i
8984 * @class Roo.bootstrap.Input
8985 * @extends Roo.bootstrap.Component
8986 * Bootstrap Input class
8987 * @cfg {Boolean} disabled is it disabled
8988 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8989 * @cfg {String} name name of the input
8990 * @cfg {string} fieldLabel - the label associated
8991 * @cfg {string} placeholder - placeholder to put in text.
8992 * @cfg {string} before - input group add on before
8993 * @cfg {string} after - input group add on after
8994 * @cfg {string} size - (lg|sm) or leave empty..
8995 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8996 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8997 * @cfg {Number} md colspan out of 12 for computer-sized screens
8998 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8999 * @cfg {string} value default value of the input
9000 * @cfg {Number} labelWidth set the width of label
9001 * @cfg {Number} labellg set the width of label (1-12)
9002 * @cfg {Number} labelmd set the width of label (1-12)
9003 * @cfg {Number} labelsm set the width of label (1-12)
9004 * @cfg {Number} labelxs set the width of label (1-12)
9005 * @cfg {String} labelAlign (top|left)
9006 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9007 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9008 * @cfg {String} indicatorpos (left|right) default left
9009 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9010 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9012 * @cfg {String} align (left|center|right) Default left
9013 * @cfg {Boolean} forceFeedback (true|false) Default false
9016 * Create a new Input
9017 * @param {Object} config The config object
9020 Roo.bootstrap.Input = function(config){
9022 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9027 * Fires when this field receives input focus.
9028 * @param {Roo.form.Field} this
9033 * Fires when this field loses input focus.
9034 * @param {Roo.form.Field} this
9039 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9040 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9041 * @param {Roo.form.Field} this
9042 * @param {Roo.EventObject} e The event object
9047 * Fires just before the field blurs if the field value has changed.
9048 * @param {Roo.form.Field} this
9049 * @param {Mixed} newValue The new value
9050 * @param {Mixed} oldValue The original value
9055 * Fires after the field has been marked as invalid.
9056 * @param {Roo.form.Field} this
9057 * @param {String} msg The validation message
9062 * Fires after the field has been validated with no errors.
9063 * @param {Roo.form.Field} this
9068 * Fires after the key up
9069 * @param {Roo.form.Field} this
9070 * @param {Roo.EventObject} e The event Object
9076 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9078 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9079 automatic validation (defaults to "keyup").
9081 validationEvent : "keyup",
9083 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9085 validateOnBlur : true,
9087 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9089 validationDelay : 250,
9091 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9093 focusClass : "x-form-focus", // not needed???
9097 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9099 invalidClass : "has-warning",
9102 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9104 validClass : "has-success",
9107 * @cfg {Boolean} hasFeedback (true|false) default true
9112 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9114 invalidFeedbackClass : "glyphicon-warning-sign",
9117 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9119 validFeedbackClass : "glyphicon-ok",
9122 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9124 selectOnFocus : false,
9127 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9131 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9136 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9138 disableKeyFilter : false,
9141 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9145 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9149 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9151 blankText : "Please complete this mandatory field",
9154 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9158 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9160 maxLength : Number.MAX_VALUE,
9162 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9164 minLengthText : "The minimum length for this field is {0}",
9166 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9168 maxLengthText : "The maximum length for this field is {0}",
9172 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9173 * If available, this function will be called only after the basic validators all return true, and will be passed the
9174 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9178 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9179 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9180 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9184 * @cfg {String} regexText -- Depricated - use Invalid Text
9189 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9195 autocomplete: false,
9214 formatedValue : false,
9215 forceFeedback : false,
9217 indicatorpos : 'left',
9227 parentLabelAlign : function()
9230 while (parent.parent()) {
9231 parent = parent.parent();
9232 if (typeof(parent.labelAlign) !='undefined') {
9233 return parent.labelAlign;
9240 getAutoCreate : function()
9242 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9248 if(this.inputType != 'hidden'){
9249 cfg.cls = 'form-group' //input-group
9255 type : this.inputType,
9257 cls : 'form-control',
9258 placeholder : this.placeholder || '',
9259 autocomplete : this.autocomplete || 'new-password'
9262 if(this.capture.length){
9263 input.capture = this.capture;
9266 if(this.accept.length){
9267 input.accept = this.accept + "/*";
9271 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9274 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9275 input.maxLength = this.maxLength;
9278 if (this.disabled) {
9279 input.disabled=true;
9282 if (this.readOnly) {
9283 input.readonly=true;
9287 input.name = this.name;
9291 input.cls += ' input-' + this.size;
9295 ['xs','sm','md','lg'].map(function(size){
9296 if (settings[size]) {
9297 cfg.cls += ' col-' + size + '-' + settings[size];
9301 var inputblock = input;
9305 cls: 'glyphicon form-control-feedback'
9308 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9311 cls : 'has-feedback',
9319 if (this.before || this.after) {
9322 cls : 'input-group',
9326 if (this.before && typeof(this.before) == 'string') {
9328 inputblock.cn.push({
9330 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9334 if (this.before && typeof(this.before) == 'object') {
9335 this.before = Roo.factory(this.before);
9337 inputblock.cn.push({
9339 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9340 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9344 inputblock.cn.push(input);
9346 if (this.after && typeof(this.after) == 'string') {
9347 inputblock.cn.push({
9349 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9353 if (this.after && typeof(this.after) == 'object') {
9354 this.after = Roo.factory(this.after);
9356 inputblock.cn.push({
9358 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9359 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9363 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9364 inputblock.cls += ' has-feedback';
9365 inputblock.cn.push(feedback);
9370 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9371 tooltip : 'This field is required'
9373 if (Roo.bootstrap.version == 4) {
9376 style : 'display-none'
9379 if (align ==='left' && this.fieldLabel.length) {
9381 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9388 cls : 'control-label col-form-label',
9389 html : this.fieldLabel
9400 var labelCfg = cfg.cn[1];
9401 var contentCfg = cfg.cn[2];
9403 if(this.indicatorpos == 'right'){
9408 cls : 'control-label col-form-label',
9412 html : this.fieldLabel
9426 labelCfg = cfg.cn[0];
9427 contentCfg = cfg.cn[1];
9431 if(this.labelWidth > 12){
9432 labelCfg.style = "width: " + this.labelWidth + 'px';
9435 if(this.labelWidth < 13 && this.labelmd == 0){
9436 this.labelmd = this.labelWidth;
9439 if(this.labellg > 0){
9440 labelCfg.cls += ' col-lg-' + this.labellg;
9441 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9444 if(this.labelmd > 0){
9445 labelCfg.cls += ' col-md-' + this.labelmd;
9446 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9449 if(this.labelsm > 0){
9450 labelCfg.cls += ' col-sm-' + this.labelsm;
9451 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9454 if(this.labelxs > 0){
9455 labelCfg.cls += ' col-xs-' + this.labelxs;
9456 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9460 } else if ( this.fieldLabel.length) {
9465 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9466 tooltip : 'This field is required'
9470 //cls : 'input-group-addon',
9471 html : this.fieldLabel
9479 if(this.indicatorpos == 'right'){
9484 //cls : 'input-group-addon',
9485 html : this.fieldLabel
9490 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9491 tooltip : 'This field is required'
9511 if (this.parentType === 'Navbar' && this.parent().bar) {
9512 cfg.cls += ' navbar-form';
9515 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9516 // on BS4 we do this only if not form
9517 cfg.cls += ' navbar-form';
9525 * return the real input element.
9527 inputEl: function ()
9529 return this.el.select('input.form-control',true).first();
9532 tooltipEl : function()
9534 return this.inputEl();
9537 indicatorEl : function()
9539 if (Roo.bootstrap.version == 4) {
9540 return false; // not enabled in v4 yet.
9543 var indicator = this.el.select('i.roo-required-indicator',true).first();
9553 setDisabled : function(v)
9555 var i = this.inputEl().dom;
9557 i.removeAttribute('disabled');
9561 i.setAttribute('disabled','true');
9563 initEvents : function()
9566 this.inputEl().on("keydown" , this.fireKey, this);
9567 this.inputEl().on("focus", this.onFocus, this);
9568 this.inputEl().on("blur", this.onBlur, this);
9570 this.inputEl().relayEvent('keyup', this);
9572 this.indicator = this.indicatorEl();
9575 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9578 // reference to original value for reset
9579 this.originalValue = this.getValue();
9580 //Roo.form.TextField.superclass.initEvents.call(this);
9581 if(this.validationEvent == 'keyup'){
9582 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9583 this.inputEl().on('keyup', this.filterValidation, this);
9585 else if(this.validationEvent !== false){
9586 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9589 if(this.selectOnFocus){
9590 this.on("focus", this.preFocus, this);
9593 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9594 this.inputEl().on("keypress", this.filterKeys, this);
9596 this.inputEl().relayEvent('keypress', this);
9599 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9600 this.el.on("click", this.autoSize, this);
9603 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9604 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9607 if (typeof(this.before) == 'object') {
9608 this.before.render(this.el.select('.roo-input-before',true).first());
9610 if (typeof(this.after) == 'object') {
9611 this.after.render(this.el.select('.roo-input-after',true).first());
9614 this.inputEl().on('change', this.onChange, this);
9617 filterValidation : function(e){
9618 if(!e.isNavKeyPress()){
9619 this.validationTask.delay(this.validationDelay);
9623 * Validates the field value
9624 * @return {Boolean} True if the value is valid, else false
9626 validate : function(){
9627 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9628 if(this.disabled || this.validateValue(this.getRawValue())){
9639 * Validates a value according to the field's validation rules and marks the field as invalid
9640 * if the validation fails
9641 * @param {Mixed} value The value to validate
9642 * @return {Boolean} True if the value is valid, else false
9644 validateValue : function(value)
9646 if(this.getVisibilityEl().hasClass('hidden')){
9650 if(value.length < 1) { // if it's blank
9651 if(this.allowBlank){
9657 if(value.length < this.minLength){
9660 if(value.length > this.maxLength){
9664 var vt = Roo.form.VTypes;
9665 if(!vt[this.vtype](value, this)){
9669 if(typeof this.validator == "function"){
9670 var msg = this.validator(value);
9674 if (typeof(msg) == 'string') {
9675 this.invalidText = msg;
9679 if(this.regex && !this.regex.test(value)){
9687 fireKey : function(e){
9688 //Roo.log('field ' + e.getKey());
9689 if(e.isNavKeyPress()){
9690 this.fireEvent("specialkey", this, e);
9693 focus : function (selectText){
9695 this.inputEl().focus();
9696 if(selectText === true){
9697 this.inputEl().dom.select();
9703 onFocus : function(){
9704 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9705 // this.el.addClass(this.focusClass);
9708 this.hasFocus = true;
9709 this.startValue = this.getValue();
9710 this.fireEvent("focus", this);
9714 beforeBlur : Roo.emptyFn,
9718 onBlur : function(){
9720 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9721 //this.el.removeClass(this.focusClass);
9723 this.hasFocus = false;
9724 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9727 var v = this.getValue();
9728 if(String(v) !== String(this.startValue)){
9729 this.fireEvent('change', this, v, this.startValue);
9731 this.fireEvent("blur", this);
9734 onChange : function(e)
9736 var v = this.getValue();
9737 if(String(v) !== String(this.startValue)){
9738 this.fireEvent('change', this, v, this.startValue);
9744 * Resets the current field value to the originally loaded value and clears any validation messages
9747 this.setValue(this.originalValue);
9751 * Returns the name of the field
9752 * @return {Mixed} name The name field
9754 getName: function(){
9758 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9759 * @return {Mixed} value The field value
9761 getValue : function(){
9763 var v = this.inputEl().getValue();
9768 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9769 * @return {Mixed} value The field value
9771 getRawValue : function(){
9772 var v = this.inputEl().getValue();
9778 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9779 * @param {Mixed} value The value to set
9781 setRawValue : function(v){
9782 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9785 selectText : function(start, end){
9786 var v = this.getRawValue();
9788 start = start === undefined ? 0 : start;
9789 end = end === undefined ? v.length : end;
9790 var d = this.inputEl().dom;
9791 if(d.setSelectionRange){
9792 d.setSelectionRange(start, end);
9793 }else if(d.createTextRange){
9794 var range = d.createTextRange();
9795 range.moveStart("character", start);
9796 range.moveEnd("character", v.length-end);
9803 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9804 * @param {Mixed} value The value to set
9806 setValue : function(v){
9809 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9815 processValue : function(value){
9816 if(this.stripCharsRe){
9817 var newValue = value.replace(this.stripCharsRe, '');
9818 if(newValue !== value){
9819 this.setRawValue(newValue);
9826 preFocus : function(){
9828 if(this.selectOnFocus){
9829 this.inputEl().dom.select();
9832 filterKeys : function(e){
9834 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9837 var c = e.getCharCode(), cc = String.fromCharCode(c);
9838 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9841 if(!this.maskRe.test(cc)){
9846 * Clear any invalid styles/messages for this field
9848 clearInvalid : function(){
9850 if(!this.el || this.preventMark){ // not rendered
9855 this.el.removeClass([this.invalidClass, 'is-invalid']);
9857 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9859 var feedback = this.el.select('.form-control-feedback', true).first();
9862 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9868 this.indicator.removeClass('visible');
9869 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9872 this.fireEvent('valid', this);
9876 * Mark this field as valid
9878 markValid : function()
9880 if(!this.el || this.preventMark){ // not rendered...
9884 this.el.removeClass([this.invalidClass, this.validClass]);
9885 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9887 var feedback = this.el.select('.form-control-feedback', true).first();
9890 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9894 this.indicator.removeClass('visible');
9895 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9902 if(this.allowBlank && !this.getRawValue().length){
9905 if (Roo.bootstrap.version == 3) {
9906 this.el.addClass(this.validClass);
9908 this.inputEl().addClass('is-valid');
9911 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9913 var feedback = this.el.select('.form-control-feedback', true).first();
9916 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9917 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9922 this.fireEvent('valid', this);
9926 * Mark this field as invalid
9927 * @param {String} msg The validation message
9929 markInvalid : function(msg)
9931 if(!this.el || this.preventMark){ // not rendered
9935 this.el.removeClass([this.invalidClass, this.validClass]);
9936 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9938 var feedback = this.el.select('.form-control-feedback', true).first();
9941 this.el.select('.form-control-feedback', true).first().removeClass(
9942 [this.invalidFeedbackClass, this.validFeedbackClass]);
9949 if(this.allowBlank && !this.getRawValue().length){
9954 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9955 this.indicator.addClass('visible');
9957 if (Roo.bootstrap.version == 3) {
9958 this.el.addClass(this.invalidClass);
9960 this.inputEl().addClass('is-invalid');
9965 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9967 var feedback = this.el.select('.form-control-feedback', true).first();
9970 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9972 if(this.getValue().length || this.forceFeedback){
9973 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9980 this.fireEvent('invalid', this, msg);
9983 SafariOnKeyDown : function(event)
9985 // this is a workaround for a password hang bug on chrome/ webkit.
9986 if (this.inputEl().dom.type != 'password') {
9990 var isSelectAll = false;
9992 if(this.inputEl().dom.selectionEnd > 0){
9993 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9995 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9996 event.preventDefault();
10001 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10003 event.preventDefault();
10004 // this is very hacky as keydown always get's upper case.
10006 var cc = String.fromCharCode(event.getCharCode());
10007 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10011 adjustWidth : function(tag, w){
10012 tag = tag.toLowerCase();
10013 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10014 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10015 if(tag == 'input'){
10018 if(tag == 'textarea'){
10021 }else if(Roo.isOpera){
10022 if(tag == 'input'){
10025 if(tag == 'textarea'){
10033 setFieldLabel : function(v)
10035 if(!this.rendered){
10039 if(this.indicatorEl()){
10040 var ar = this.el.select('label > span',true);
10042 if (ar.elements.length) {
10043 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10044 this.fieldLabel = v;
10048 var br = this.el.select('label',true);
10050 if(br.elements.length) {
10051 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10052 this.fieldLabel = v;
10056 Roo.log('Cannot Found any of label > span || label in input');
10060 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10061 this.fieldLabel = v;
10076 * @class Roo.bootstrap.TextArea
10077 * @extends Roo.bootstrap.Input
10078 * Bootstrap TextArea class
10079 * @cfg {Number} cols Specifies the visible width of a text area
10080 * @cfg {Number} rows Specifies the visible number of lines in a text area
10081 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10082 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10083 * @cfg {string} html text
10086 * Create a new TextArea
10087 * @param {Object} config The config object
10090 Roo.bootstrap.TextArea = function(config){
10091 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10095 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10105 getAutoCreate : function(){
10107 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10113 if(this.inputType != 'hidden'){
10114 cfg.cls = 'form-group' //input-group
10122 value : this.value || '',
10123 html: this.html || '',
10124 cls : 'form-control',
10125 placeholder : this.placeholder || ''
10129 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10130 input.maxLength = this.maxLength;
10134 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10138 input.cols = this.cols;
10141 if (this.readOnly) {
10142 input.readonly = true;
10146 input.name = this.name;
10150 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10154 ['xs','sm','md','lg'].map(function(size){
10155 if (settings[size]) {
10156 cfg.cls += ' col-' + size + '-' + settings[size];
10160 var inputblock = input;
10162 if(this.hasFeedback && !this.allowBlank){
10166 cls: 'glyphicon form-control-feedback'
10170 cls : 'has-feedback',
10179 if (this.before || this.after) {
10182 cls : 'input-group',
10186 inputblock.cn.push({
10188 cls : 'input-group-addon',
10193 inputblock.cn.push(input);
10195 if(this.hasFeedback && !this.allowBlank){
10196 inputblock.cls += ' has-feedback';
10197 inputblock.cn.push(feedback);
10201 inputblock.cn.push({
10203 cls : 'input-group-addon',
10210 if (align ==='left' && this.fieldLabel.length) {
10215 cls : 'control-label',
10216 html : this.fieldLabel
10227 if(this.labelWidth > 12){
10228 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10231 if(this.labelWidth < 13 && this.labelmd == 0){
10232 this.labelmd = this.labelWidth;
10235 if(this.labellg > 0){
10236 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10237 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10240 if(this.labelmd > 0){
10241 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10242 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10245 if(this.labelsm > 0){
10246 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10247 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10250 if(this.labelxs > 0){
10251 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10252 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10255 } else if ( this.fieldLabel.length) {
10260 //cls : 'input-group-addon',
10261 html : this.fieldLabel
10279 if (this.disabled) {
10280 input.disabled=true;
10287 * return the real textarea element.
10289 inputEl: function ()
10291 return this.el.select('textarea.form-control',true).first();
10295 * Clear any invalid styles/messages for this field
10297 clearInvalid : function()
10300 if(!this.el || this.preventMark){ // not rendered
10304 var label = this.el.select('label', true).first();
10305 var icon = this.el.select('i.fa-star', true).first();
10310 this.el.removeClass( this.validClass);
10311 this.inputEl().removeClass('is-invalid');
10313 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10315 var feedback = this.el.select('.form-control-feedback', true).first();
10318 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10323 this.fireEvent('valid', this);
10327 * Mark this field as valid
10329 markValid : function()
10331 if(!this.el || this.preventMark){ // not rendered
10335 this.el.removeClass([this.invalidClass, this.validClass]);
10336 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10338 var feedback = this.el.select('.form-control-feedback', true).first();
10341 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10344 if(this.disabled || this.allowBlank){
10348 var label = this.el.select('label', true).first();
10349 var icon = this.el.select('i.fa-star', true).first();
10354 if (Roo.bootstrap.version == 3) {
10355 this.el.addClass(this.validClass);
10357 this.inputEl().addClass('is-valid');
10361 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10363 var feedback = this.el.select('.form-control-feedback', true).first();
10366 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10367 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10372 this.fireEvent('valid', this);
10376 * Mark this field as invalid
10377 * @param {String} msg The validation message
10379 markInvalid : function(msg)
10381 if(!this.el || this.preventMark){ // not rendered
10385 this.el.removeClass([this.invalidClass, this.validClass]);
10386 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10388 var feedback = this.el.select('.form-control-feedback', true).first();
10391 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10394 if(this.disabled || this.allowBlank){
10398 var label = this.el.select('label', true).first();
10399 var icon = this.el.select('i.fa-star', true).first();
10401 if(!this.getValue().length && label && !icon){
10402 this.el.createChild({
10404 cls : 'text-danger fa fa-lg fa-star',
10405 tooltip : 'This field is required',
10406 style : 'margin-right:5px;'
10410 if (Roo.bootstrap.version == 3) {
10411 this.el.addClass(this.invalidClass);
10413 this.inputEl().addClass('is-invalid');
10416 // fixme ... this may be depricated need to test..
10417 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10419 var feedback = this.el.select('.form-control-feedback', true).first();
10422 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10424 if(this.getValue().length || this.forceFeedback){
10425 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10432 this.fireEvent('invalid', this, msg);
10440 * trigger field - base class for combo..
10445 * @class Roo.bootstrap.TriggerField
10446 * @extends Roo.bootstrap.Input
10447 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10448 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10449 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10450 * for which you can provide a custom implementation. For example:
10452 var trigger = new Roo.bootstrap.TriggerField();
10453 trigger.onTriggerClick = myTriggerFn;
10454 trigger.applyTo('my-field');
10457 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10458 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10459 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10460 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10461 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
10464 * Create a new TriggerField.
10465 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10466 * to the base TextField)
10468 Roo.bootstrap.TriggerField = function(config){
10469 this.mimicing = false;
10470 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10473 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10475 * @cfg {String} triggerClass A CSS class to apply to the trigger
10478 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10483 * @cfg {Boolean} removable (true|false) special filter default false
10487 /** @cfg {Boolean} grow @hide */
10488 /** @cfg {Number} growMin @hide */
10489 /** @cfg {Number} growMax @hide */
10495 autoSize: Roo.emptyFn,
10499 deferHeight : true,
10502 actionMode : 'wrap',
10507 getAutoCreate : function(){
10509 var align = this.labelAlign || this.parentLabelAlign();
10514 cls: 'form-group' //input-group
10521 type : this.inputType,
10522 cls : 'form-control',
10523 autocomplete: 'new-password',
10524 placeholder : this.placeholder || ''
10528 input.name = this.name;
10531 input.cls += ' input-' + this.size;
10534 if (this.disabled) {
10535 input.disabled=true;
10538 var inputblock = input;
10540 if(this.hasFeedback && !this.allowBlank){
10544 cls: 'glyphicon form-control-feedback'
10547 if(this.removable && !this.editable && !this.tickable){
10549 cls : 'has-feedback',
10555 cls : 'roo-combo-removable-btn close'
10562 cls : 'has-feedback',
10571 if(this.removable && !this.editable && !this.tickable){
10573 cls : 'roo-removable',
10579 cls : 'roo-combo-removable-btn close'
10586 if (this.before || this.after) {
10589 cls : 'input-group',
10593 inputblock.cn.push({
10595 cls : 'input-group-addon input-group-prepend input-group-text',
10600 inputblock.cn.push(input);
10602 if(this.hasFeedback && !this.allowBlank){
10603 inputblock.cls += ' has-feedback';
10604 inputblock.cn.push(feedback);
10608 inputblock.cn.push({
10610 cls : 'input-group-addon input-group-append input-group-text',
10619 var ibwrap = inputblock;
10624 cls: 'roo-select2-choices',
10628 cls: 'roo-select2-search-field',
10640 cls: 'roo-select2-container input-group',
10645 cls: 'form-hidden-field'
10651 if(!this.multiple && this.showToggleBtn){
10657 if (this.caret != false) {
10660 cls: 'fa fa-' + this.caret
10667 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10669 Roo.bootstrap.version == 3 ? caret : '',
10672 cls: 'combobox-clear',
10686 combobox.cls += ' roo-select2-container-multi';
10690 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10691 tooltip : 'This field is required'
10693 if (Roo.bootstrap.version == 4) {
10696 style : 'display:none'
10701 if (align ==='left' && this.fieldLabel.length) {
10703 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10710 cls : 'control-label',
10711 html : this.fieldLabel
10723 var labelCfg = cfg.cn[1];
10724 var contentCfg = cfg.cn[2];
10726 if(this.indicatorpos == 'right'){
10731 cls : 'control-label',
10735 html : this.fieldLabel
10749 labelCfg = cfg.cn[0];
10750 contentCfg = cfg.cn[1];
10753 if(this.labelWidth > 12){
10754 labelCfg.style = "width: " + this.labelWidth + 'px';
10757 if(this.labelWidth < 13 && this.labelmd == 0){
10758 this.labelmd = this.labelWidth;
10761 if(this.labellg > 0){
10762 labelCfg.cls += ' col-lg-' + this.labellg;
10763 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10766 if(this.labelmd > 0){
10767 labelCfg.cls += ' col-md-' + this.labelmd;
10768 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10771 if(this.labelsm > 0){
10772 labelCfg.cls += ' col-sm-' + this.labelsm;
10773 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10776 if(this.labelxs > 0){
10777 labelCfg.cls += ' col-xs-' + this.labelxs;
10778 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10781 } else if ( this.fieldLabel.length) {
10782 // Roo.log(" label");
10787 //cls : 'input-group-addon',
10788 html : this.fieldLabel
10796 if(this.indicatorpos == 'right'){
10804 html : this.fieldLabel
10818 // Roo.log(" no label && no align");
10825 ['xs','sm','md','lg'].map(function(size){
10826 if (settings[size]) {
10827 cfg.cls += ' col-' + size + '-' + settings[size];
10838 onResize : function(w, h){
10839 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10840 // if(typeof w == 'number'){
10841 // var x = w - this.trigger.getWidth();
10842 // this.inputEl().setWidth(this.adjustWidth('input', x));
10843 // this.trigger.setStyle('left', x+'px');
10848 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10851 getResizeEl : function(){
10852 return this.inputEl();
10856 getPositionEl : function(){
10857 return this.inputEl();
10861 alignErrorIcon : function(){
10862 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10866 initEvents : function(){
10870 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10871 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10872 if(!this.multiple && this.showToggleBtn){
10873 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10874 if(this.hideTrigger){
10875 this.trigger.setDisplayed(false);
10877 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10881 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10884 if(this.removable && !this.editable && !this.tickable){
10885 var close = this.closeTriggerEl();
10888 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10889 close.on('click', this.removeBtnClick, this, close);
10893 //this.trigger.addClassOnOver('x-form-trigger-over');
10894 //this.trigger.addClassOnClick('x-form-trigger-click');
10897 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10901 closeTriggerEl : function()
10903 var close = this.el.select('.roo-combo-removable-btn', true).first();
10904 return close ? close : false;
10907 removeBtnClick : function(e, h, el)
10909 e.preventDefault();
10911 if(this.fireEvent("remove", this) !== false){
10913 this.fireEvent("afterremove", this)
10917 createList : function()
10919 this.list = Roo.get(document.body).createChild({
10920 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10921 cls: 'typeahead typeahead-long dropdown-menu',
10922 style: 'display:none'
10925 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10930 initTrigger : function(){
10935 onDestroy : function(){
10937 this.trigger.removeAllListeners();
10938 // this.trigger.remove();
10941 // this.wrap.remove();
10943 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10947 onFocus : function(){
10948 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10950 if(!this.mimicing){
10951 this.wrap.addClass('x-trigger-wrap-focus');
10952 this.mimicing = true;
10953 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10954 if(this.monitorTab){
10955 this.el.on("keydown", this.checkTab, this);
10962 checkTab : function(e){
10963 if(e.getKey() == e.TAB){
10964 this.triggerBlur();
10969 onBlur : function(){
10974 mimicBlur : function(e, t){
10976 if(!this.wrap.contains(t) && this.validateBlur()){
10977 this.triggerBlur();
10983 triggerBlur : function(){
10984 this.mimicing = false;
10985 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10986 if(this.monitorTab){
10987 this.el.un("keydown", this.checkTab, this);
10989 //this.wrap.removeClass('x-trigger-wrap-focus');
10990 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10994 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10995 validateBlur : function(e, t){
11000 onDisable : function(){
11001 this.inputEl().dom.disabled = true;
11002 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11004 // this.wrap.addClass('x-item-disabled');
11009 onEnable : function(){
11010 this.inputEl().dom.disabled = false;
11011 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11013 // this.el.removeClass('x-item-disabled');
11018 onShow : function(){
11019 var ae = this.getActionEl();
11022 ae.dom.style.display = '';
11023 ae.dom.style.visibility = 'visible';
11029 onHide : function(){
11030 var ae = this.getActionEl();
11031 ae.dom.style.display = 'none';
11035 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11036 * by an implementing function.
11038 * @param {EventObject} e
11040 onTriggerClick : Roo.emptyFn
11044 * Ext JS Library 1.1.1
11045 * Copyright(c) 2006-2007, Ext JS, LLC.
11047 * Originally Released Under LGPL - original licence link has changed is not relivant.
11050 * <script type="text/javascript">
11055 * @class Roo.data.SortTypes
11057 * Defines the default sorting (casting?) comparison functions used when sorting data.
11059 Roo.data.SortTypes = {
11061 * Default sort that does nothing
11062 * @param {Mixed} s The value being converted
11063 * @return {Mixed} The comparison value
11065 none : function(s){
11070 * The regular expression used to strip tags
11074 stripTagsRE : /<\/?[^>]+>/gi,
11077 * Strips all HTML tags to sort on text only
11078 * @param {Mixed} s The value being converted
11079 * @return {String} The comparison value
11081 asText : function(s){
11082 return String(s).replace(this.stripTagsRE, "");
11086 * Strips all HTML tags to sort on text only - Case insensitive
11087 * @param {Mixed} s The value being converted
11088 * @return {String} The comparison value
11090 asUCText : function(s){
11091 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11095 * Case insensitive string
11096 * @param {Mixed} s The value being converted
11097 * @return {String} The comparison value
11099 asUCString : function(s) {
11100 return String(s).toUpperCase();
11105 * @param {Mixed} s The value being converted
11106 * @return {Number} The comparison value
11108 asDate : function(s) {
11112 if(s instanceof Date){
11113 return s.getTime();
11115 return Date.parse(String(s));
11120 * @param {Mixed} s The value being converted
11121 * @return {Float} The comparison value
11123 asFloat : function(s) {
11124 var val = parseFloat(String(s).replace(/,/g, ""));
11133 * @param {Mixed} s The value being converted
11134 * @return {Number} The comparison value
11136 asInt : function(s) {
11137 var val = parseInt(String(s).replace(/,/g, ""));
11145 * Ext JS Library 1.1.1
11146 * Copyright(c) 2006-2007, Ext JS, LLC.
11148 * Originally Released Under LGPL - original licence link has changed is not relivant.
11151 * <script type="text/javascript">
11155 * @class Roo.data.Record
11156 * Instances of this class encapsulate both record <em>definition</em> information, and record
11157 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11158 * to access Records cached in an {@link Roo.data.Store} object.<br>
11160 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11161 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11164 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11166 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11167 * {@link #create}. The parameters are the same.
11168 * @param {Array} data An associative Array of data values keyed by the field name.
11169 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11170 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11171 * not specified an integer id is generated.
11173 Roo.data.Record = function(data, id){
11174 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11179 * Generate a constructor for a specific record layout.
11180 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11181 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11182 * Each field definition object may contain the following properties: <ul>
11183 * <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,
11184 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11185 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11186 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11187 * is being used, then this is a string containing the javascript expression to reference the data relative to
11188 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11189 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11190 * this may be omitted.</p></li>
11191 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11192 * <ul><li>auto (Default, implies no conversion)</li>
11197 * <li>date</li></ul></p></li>
11198 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11199 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11200 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11201 * by the Reader into an object that will be stored in the Record. It is passed the
11202 * following parameters:<ul>
11203 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11205 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11207 * <br>usage:<br><pre><code>
11208 var TopicRecord = Roo.data.Record.create(
11209 {name: 'title', mapping: 'topic_title'},
11210 {name: 'author', mapping: 'username'},
11211 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11212 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11213 {name: 'lastPoster', mapping: 'user2'},
11214 {name: 'excerpt', mapping: 'post_text'}
11217 var myNewRecord = new TopicRecord({
11218 title: 'Do my job please',
11221 lastPost: new Date(),
11222 lastPoster: 'Animal',
11223 excerpt: 'No way dude!'
11225 myStore.add(myNewRecord);
11230 Roo.data.Record.create = function(o){
11231 var f = function(){
11232 f.superclass.constructor.apply(this, arguments);
11234 Roo.extend(f, Roo.data.Record);
11235 var p = f.prototype;
11236 p.fields = new Roo.util.MixedCollection(false, function(field){
11239 for(var i = 0, len = o.length; i < len; i++){
11240 p.fields.add(new Roo.data.Field(o[i]));
11242 f.getField = function(name){
11243 return p.fields.get(name);
11248 Roo.data.Record.AUTO_ID = 1000;
11249 Roo.data.Record.EDIT = 'edit';
11250 Roo.data.Record.REJECT = 'reject';
11251 Roo.data.Record.COMMIT = 'commit';
11253 Roo.data.Record.prototype = {
11255 * Readonly flag - true if this record has been modified.
11264 join : function(store){
11265 this.store = store;
11269 * Set the named field to the specified value.
11270 * @param {String} name The name of the field to set.
11271 * @param {Object} value The value to set the field to.
11273 set : function(name, value){
11274 if(this.data[name] == value){
11278 if(!this.modified){
11279 this.modified = {};
11281 if(typeof this.modified[name] == 'undefined'){
11282 this.modified[name] = this.data[name];
11284 this.data[name] = value;
11285 if(!this.editing && this.store){
11286 this.store.afterEdit(this);
11291 * Get the value of the named field.
11292 * @param {String} name The name of the field to get the value of.
11293 * @return {Object} The value of the field.
11295 get : function(name){
11296 return this.data[name];
11300 beginEdit : function(){
11301 this.editing = true;
11302 this.modified = {};
11306 cancelEdit : function(){
11307 this.editing = false;
11308 delete this.modified;
11312 endEdit : function(){
11313 this.editing = false;
11314 if(this.dirty && this.store){
11315 this.store.afterEdit(this);
11320 * Usually called by the {@link Roo.data.Store} which owns the Record.
11321 * Rejects all changes made to the Record since either creation, or the last commit operation.
11322 * Modified fields are reverted to their original values.
11324 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11325 * of reject operations.
11327 reject : function(){
11328 var m = this.modified;
11330 if(typeof m[n] != "function"){
11331 this.data[n] = m[n];
11334 this.dirty = false;
11335 delete this.modified;
11336 this.editing = false;
11338 this.store.afterReject(this);
11343 * Usually called by the {@link Roo.data.Store} which owns the Record.
11344 * Commits all changes made to the Record since either creation, or the last commit operation.
11346 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11347 * of commit operations.
11349 commit : function(){
11350 this.dirty = false;
11351 delete this.modified;
11352 this.editing = false;
11354 this.store.afterCommit(this);
11359 hasError : function(){
11360 return this.error != null;
11364 clearError : function(){
11369 * Creates a copy of this record.
11370 * @param {String} id (optional) A new record id if you don't want to use this record's id
11373 copy : function(newId) {
11374 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11378 * Ext JS Library 1.1.1
11379 * Copyright(c) 2006-2007, Ext JS, LLC.
11381 * Originally Released Under LGPL - original licence link has changed is not relivant.
11384 * <script type="text/javascript">
11390 * @class Roo.data.Store
11391 * @extends Roo.util.Observable
11392 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11393 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11395 * 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
11396 * has no knowledge of the format of the data returned by the Proxy.<br>
11398 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11399 * instances from the data object. These records are cached and made available through accessor functions.
11401 * Creates a new Store.
11402 * @param {Object} config A config object containing the objects needed for the Store to access data,
11403 * and read the data into Records.
11405 Roo.data.Store = function(config){
11406 this.data = new Roo.util.MixedCollection(false);
11407 this.data.getKey = function(o){
11410 this.baseParams = {};
11412 this.paramNames = {
11417 "multisort" : "_multisort"
11420 if(config && config.data){
11421 this.inlineData = config.data;
11422 delete config.data;
11425 Roo.apply(this, config);
11427 if(this.reader){ // reader passed
11428 this.reader = Roo.factory(this.reader, Roo.data);
11429 this.reader.xmodule = this.xmodule || false;
11430 if(!this.recordType){
11431 this.recordType = this.reader.recordType;
11433 if(this.reader.onMetaChange){
11434 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11438 if(this.recordType){
11439 this.fields = this.recordType.prototype.fields;
11441 this.modified = [];
11445 * @event datachanged
11446 * Fires when the data cache has changed, and a widget which is using this Store
11447 * as a Record cache should refresh its view.
11448 * @param {Store} this
11450 datachanged : true,
11452 * @event metachange
11453 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11454 * @param {Store} this
11455 * @param {Object} meta The JSON metadata
11460 * Fires when Records have been added to the Store
11461 * @param {Store} this
11462 * @param {Roo.data.Record[]} records The array of Records added
11463 * @param {Number} index The index at which the record(s) were added
11468 * Fires when a Record has been removed from the Store
11469 * @param {Store} this
11470 * @param {Roo.data.Record} record The Record that was removed
11471 * @param {Number} index The index at which the record was removed
11476 * Fires when a Record has been updated
11477 * @param {Store} this
11478 * @param {Roo.data.Record} record The Record that was updated
11479 * @param {String} operation The update operation being performed. Value may be one of:
11481 Roo.data.Record.EDIT
11482 Roo.data.Record.REJECT
11483 Roo.data.Record.COMMIT
11489 * Fires when the data cache has been cleared.
11490 * @param {Store} this
11494 * @event beforeload
11495 * Fires before a request is made for a new data object. If the beforeload handler returns false
11496 * the load action will be canceled.
11497 * @param {Store} this
11498 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11502 * @event beforeloadadd
11503 * Fires after a new set of Records has been loaded.
11504 * @param {Store} this
11505 * @param {Roo.data.Record[]} records The Records that were loaded
11506 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11508 beforeloadadd : true,
11511 * Fires after a new set of Records has been loaded, before they are added to the store.
11512 * @param {Store} this
11513 * @param {Roo.data.Record[]} records The Records that were loaded
11514 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11515 * @params {Object} return from reader
11519 * @event loadexception
11520 * Fires if an exception occurs in the Proxy during loading.
11521 * Called with the signature of the Proxy's "loadexception" event.
11522 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11525 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11526 * @param {Object} load options
11527 * @param {Object} jsonData from your request (normally this contains the Exception)
11529 loadexception : true
11533 this.proxy = Roo.factory(this.proxy, Roo.data);
11534 this.proxy.xmodule = this.xmodule || false;
11535 this.relayEvents(this.proxy, ["loadexception"]);
11537 this.sortToggle = {};
11538 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11540 Roo.data.Store.superclass.constructor.call(this);
11542 if(this.inlineData){
11543 this.loadData(this.inlineData);
11544 delete this.inlineData;
11548 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11550 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11551 * without a remote query - used by combo/forms at present.
11555 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11558 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11561 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11562 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11565 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11566 * on any HTTP request
11569 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11572 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11576 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11577 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11579 remoteSort : false,
11582 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11583 * loaded or when a record is removed. (defaults to false).
11585 pruneModifiedRecords : false,
11588 lastOptions : null,
11591 * Add Records to the Store and fires the add event.
11592 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11594 add : function(records){
11595 records = [].concat(records);
11596 for(var i = 0, len = records.length; i < len; i++){
11597 records[i].join(this);
11599 var index = this.data.length;
11600 this.data.addAll(records);
11601 this.fireEvent("add", this, records, index);
11605 * Remove a Record from the Store and fires the remove event.
11606 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11608 remove : function(record){
11609 var index = this.data.indexOf(record);
11610 this.data.removeAt(index);
11612 if(this.pruneModifiedRecords){
11613 this.modified.remove(record);
11615 this.fireEvent("remove", this, record, index);
11619 * Remove all Records from the Store and fires the clear event.
11621 removeAll : function(){
11623 if(this.pruneModifiedRecords){
11624 this.modified = [];
11626 this.fireEvent("clear", this);
11630 * Inserts Records to the Store at the given index and fires the add event.
11631 * @param {Number} index The start index at which to insert the passed Records.
11632 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11634 insert : function(index, records){
11635 records = [].concat(records);
11636 for(var i = 0, len = records.length; i < len; i++){
11637 this.data.insert(index, records[i]);
11638 records[i].join(this);
11640 this.fireEvent("add", this, records, index);
11644 * Get the index within the cache of the passed Record.
11645 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11646 * @return {Number} The index of the passed Record. Returns -1 if not found.
11648 indexOf : function(record){
11649 return this.data.indexOf(record);
11653 * Get the index within the cache of the Record with the passed id.
11654 * @param {String} id The id of the Record to find.
11655 * @return {Number} The index of the Record. Returns -1 if not found.
11657 indexOfId : function(id){
11658 return this.data.indexOfKey(id);
11662 * Get the Record with the specified id.
11663 * @param {String} id The id of the Record to find.
11664 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11666 getById : function(id){
11667 return this.data.key(id);
11671 * Get the Record at the specified index.
11672 * @param {Number} index The index of the Record to find.
11673 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11675 getAt : function(index){
11676 return this.data.itemAt(index);
11680 * Returns a range of Records between specified indices.
11681 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11682 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11683 * @return {Roo.data.Record[]} An array of Records
11685 getRange : function(start, end){
11686 return this.data.getRange(start, end);
11690 storeOptions : function(o){
11691 o = Roo.apply({}, o);
11694 this.lastOptions = o;
11698 * Loads the Record cache from the configured Proxy using the configured Reader.
11700 * If using remote paging, then the first load call must specify the <em>start</em>
11701 * and <em>limit</em> properties in the options.params property to establish the initial
11702 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11704 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11705 * and this call will return before the new data has been loaded. Perform any post-processing
11706 * in a callback function, or in a "load" event handler.</strong>
11708 * @param {Object} options An object containing properties which control loading options:<ul>
11709 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11710 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11711 * passed the following arguments:<ul>
11712 * <li>r : Roo.data.Record[]</li>
11713 * <li>options: Options object from the load call</li>
11714 * <li>success: Boolean success indicator</li></ul></li>
11715 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11716 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11719 load : function(options){
11720 options = options || {};
11721 if(this.fireEvent("beforeload", this, options) !== false){
11722 this.storeOptions(options);
11723 var p = Roo.apply(options.params || {}, this.baseParams);
11724 // if meta was not loaded from remote source.. try requesting it.
11725 if (!this.reader.metaFromRemote) {
11726 p._requestMeta = 1;
11728 if(this.sortInfo && this.remoteSort){
11729 var pn = this.paramNames;
11730 p[pn["sort"]] = this.sortInfo.field;
11731 p[pn["dir"]] = this.sortInfo.direction;
11733 if (this.multiSort) {
11734 var pn = this.paramNames;
11735 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11738 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11743 * Reloads the Record cache from the configured Proxy using the configured Reader and
11744 * the options from the last load operation performed.
11745 * @param {Object} options (optional) An object containing properties which may override the options
11746 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11747 * the most recently used options are reused).
11749 reload : function(options){
11750 this.load(Roo.applyIf(options||{}, this.lastOptions));
11754 // Called as a callback by the Reader during a load operation.
11755 loadRecords : function(o, options, success){
11756 if(!o || success === false){
11757 if(success !== false){
11758 this.fireEvent("load", this, [], options, o);
11760 if(options.callback){
11761 options.callback.call(options.scope || this, [], options, false);
11765 // if data returned failure - throw an exception.
11766 if (o.success === false) {
11767 // show a message if no listener is registered.
11768 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11769 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11771 // loadmask wil be hooked into this..
11772 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11775 var r = o.records, t = o.totalRecords || r.length;
11777 this.fireEvent("beforeloadadd", this, r, options, o);
11779 if(!options || options.add !== true){
11780 if(this.pruneModifiedRecords){
11781 this.modified = [];
11783 for(var i = 0, len = r.length; i < len; i++){
11787 this.data = this.snapshot;
11788 delete this.snapshot;
11791 this.data.addAll(r);
11792 this.totalLength = t;
11794 this.fireEvent("datachanged", this);
11796 this.totalLength = Math.max(t, this.data.length+r.length);
11800 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11802 var e = new Roo.data.Record({});
11804 e.set(this.parent.displayField, this.parent.emptyTitle);
11805 e.set(this.parent.valueField, '');
11810 this.fireEvent("load", this, r, options, o);
11811 if(options.callback){
11812 options.callback.call(options.scope || this, r, options, true);
11818 * Loads data from a passed data block. A Reader which understands the format of the data
11819 * must have been configured in the constructor.
11820 * @param {Object} data The data block from which to read the Records. The format of the data expected
11821 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11822 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11824 loadData : function(o, append){
11825 var r = this.reader.readRecords(o);
11826 this.loadRecords(r, {add: append}, true);
11830 * Gets the number of cached records.
11832 * <em>If using paging, this may not be the total size of the dataset. If the data object
11833 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11834 * the data set size</em>
11836 getCount : function(){
11837 return this.data.length || 0;
11841 * Gets the total number of records in the dataset as returned by the server.
11843 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11844 * the dataset size</em>
11846 getTotalCount : function(){
11847 return this.totalLength || 0;
11851 * Returns the sort state of the Store as an object with two properties:
11853 field {String} The name of the field by which the Records are sorted
11854 direction {String} The sort order, "ASC" or "DESC"
11857 getSortState : function(){
11858 return this.sortInfo;
11862 applySort : function(){
11863 if(this.sortInfo && !this.remoteSort){
11864 var s = this.sortInfo, f = s.field;
11865 var st = this.fields.get(f).sortType;
11866 var fn = function(r1, r2){
11867 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11868 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11870 this.data.sort(s.direction, fn);
11871 if(this.snapshot && this.snapshot != this.data){
11872 this.snapshot.sort(s.direction, fn);
11878 * Sets the default sort column and order to be used by the next load operation.
11879 * @param {String} fieldName The name of the field to sort by.
11880 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11882 setDefaultSort : function(field, dir){
11883 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11887 * Sort the Records.
11888 * If remote sorting is used, the sort is performed on the server, and the cache is
11889 * reloaded. If local sorting is used, the cache is sorted internally.
11890 * @param {String} fieldName The name of the field to sort by.
11891 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11893 sort : function(fieldName, dir){
11894 var f = this.fields.get(fieldName);
11896 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11898 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11899 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11904 this.sortToggle[f.name] = dir;
11905 this.sortInfo = {field: f.name, direction: dir};
11906 if(!this.remoteSort){
11908 this.fireEvent("datachanged", this);
11910 this.load(this.lastOptions);
11915 * Calls the specified function for each of the Records in the cache.
11916 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11917 * Returning <em>false</em> aborts and exits the iteration.
11918 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11920 each : function(fn, scope){
11921 this.data.each(fn, scope);
11925 * Gets all records modified since the last commit. Modified records are persisted across load operations
11926 * (e.g., during paging).
11927 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11929 getModifiedRecords : function(){
11930 return this.modified;
11934 createFilterFn : function(property, value, anyMatch){
11935 if(!value.exec){ // not a regex
11936 value = String(value);
11937 if(value.length == 0){
11940 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11942 return function(r){
11943 return value.test(r.data[property]);
11948 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11949 * @param {String} property A field on your records
11950 * @param {Number} start The record index to start at (defaults to 0)
11951 * @param {Number} end The last record index to include (defaults to length - 1)
11952 * @return {Number} The sum
11954 sum : function(property, start, end){
11955 var rs = this.data.items, v = 0;
11956 start = start || 0;
11957 end = (end || end === 0) ? end : rs.length-1;
11959 for(var i = start; i <= end; i++){
11960 v += (rs[i].data[property] || 0);
11966 * Filter the records by a specified property.
11967 * @param {String} field A field on your records
11968 * @param {String/RegExp} value Either a string that the field
11969 * should start with or a RegExp to test against the field
11970 * @param {Boolean} anyMatch True to match any part not just the beginning
11972 filter : function(property, value, anyMatch){
11973 var fn = this.createFilterFn(property, value, anyMatch);
11974 return fn ? this.filterBy(fn) : this.clearFilter();
11978 * Filter by a function. The specified function will be called with each
11979 * record in this data source. If the function returns true the record is included,
11980 * otherwise it is filtered.
11981 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11982 * @param {Object} scope (optional) The scope of the function (defaults to this)
11984 filterBy : function(fn, scope){
11985 this.snapshot = this.snapshot || this.data;
11986 this.data = this.queryBy(fn, scope||this);
11987 this.fireEvent("datachanged", this);
11991 * Query the records by a specified property.
11992 * @param {String} field A field on your records
11993 * @param {String/RegExp} value Either a string that the field
11994 * should start with or a RegExp to test against the field
11995 * @param {Boolean} anyMatch True to match any part not just the beginning
11996 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11998 query : function(property, value, anyMatch){
11999 var fn = this.createFilterFn(property, value, anyMatch);
12000 return fn ? this.queryBy(fn) : this.data.clone();
12004 * Query by a function. The specified function will be called with each
12005 * record in this data source. If the function returns true the record is included
12007 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12008 * @param {Object} scope (optional) The scope of the function (defaults to this)
12009 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12011 queryBy : function(fn, scope){
12012 var data = this.snapshot || this.data;
12013 return data.filterBy(fn, scope||this);
12017 * Collects unique values for a particular dataIndex from this store.
12018 * @param {String} dataIndex The property to collect
12019 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12020 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12021 * @return {Array} An array of the unique values
12023 collect : function(dataIndex, allowNull, bypassFilter){
12024 var d = (bypassFilter === true && this.snapshot) ?
12025 this.snapshot.items : this.data.items;
12026 var v, sv, r = [], l = {};
12027 for(var i = 0, len = d.length; i < len; i++){
12028 v = d[i].data[dataIndex];
12030 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12039 * Revert to a view of the Record cache with no filtering applied.
12040 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12042 clearFilter : function(suppressEvent){
12043 if(this.snapshot && this.snapshot != this.data){
12044 this.data = this.snapshot;
12045 delete this.snapshot;
12046 if(suppressEvent !== true){
12047 this.fireEvent("datachanged", this);
12053 afterEdit : function(record){
12054 if(this.modified.indexOf(record) == -1){
12055 this.modified.push(record);
12057 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12061 afterReject : function(record){
12062 this.modified.remove(record);
12063 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12067 afterCommit : function(record){
12068 this.modified.remove(record);
12069 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12073 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12074 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12076 commitChanges : function(){
12077 var m = this.modified.slice(0);
12078 this.modified = [];
12079 for(var i = 0, len = m.length; i < len; i++){
12085 * Cancel outstanding changes on all changed records.
12087 rejectChanges : function(){
12088 var m = this.modified.slice(0);
12089 this.modified = [];
12090 for(var i = 0, len = m.length; i < len; i++){
12095 onMetaChange : function(meta, rtype, o){
12096 this.recordType = rtype;
12097 this.fields = rtype.prototype.fields;
12098 delete this.snapshot;
12099 this.sortInfo = meta.sortInfo || this.sortInfo;
12100 this.modified = [];
12101 this.fireEvent('metachange', this, this.reader.meta);
12104 moveIndex : function(data, type)
12106 var index = this.indexOf(data);
12108 var newIndex = index + type;
12112 this.insert(newIndex, data);
12117 * Ext JS Library 1.1.1
12118 * Copyright(c) 2006-2007, Ext JS, LLC.
12120 * Originally Released Under LGPL - original licence link has changed is not relivant.
12123 * <script type="text/javascript">
12127 * @class Roo.data.SimpleStore
12128 * @extends Roo.data.Store
12129 * Small helper class to make creating Stores from Array data easier.
12130 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12131 * @cfg {Array} fields An array of field definition objects, or field name strings.
12132 * @cfg {Array} data The multi-dimensional array of data
12134 * @param {Object} config
12136 Roo.data.SimpleStore = function(config){
12137 Roo.data.SimpleStore.superclass.constructor.call(this, {
12139 reader: new Roo.data.ArrayReader({
12142 Roo.data.Record.create(config.fields)
12144 proxy : new Roo.data.MemoryProxy(config.data)
12148 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12150 * Ext JS Library 1.1.1
12151 * Copyright(c) 2006-2007, Ext JS, LLC.
12153 * Originally Released Under LGPL - original licence link has changed is not relivant.
12156 * <script type="text/javascript">
12161 * @extends Roo.data.Store
12162 * @class Roo.data.JsonStore
12163 * Small helper class to make creating Stores for JSON data easier. <br/>
12165 var store = new Roo.data.JsonStore({
12166 url: 'get-images.php',
12168 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12171 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12172 * JsonReader and HttpProxy (unless inline data is provided).</b>
12173 * @cfg {Array} fields An array of field definition objects, or field name strings.
12175 * @param {Object} config
12177 Roo.data.JsonStore = function(c){
12178 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12179 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12180 reader: new Roo.data.JsonReader(c, c.fields)
12183 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12185 * Ext JS Library 1.1.1
12186 * Copyright(c) 2006-2007, Ext JS, LLC.
12188 * Originally Released Under LGPL - original licence link has changed is not relivant.
12191 * <script type="text/javascript">
12195 Roo.data.Field = function(config){
12196 if(typeof config == "string"){
12197 config = {name: config};
12199 Roo.apply(this, config);
12202 this.type = "auto";
12205 var st = Roo.data.SortTypes;
12206 // named sortTypes are supported, here we look them up
12207 if(typeof this.sortType == "string"){
12208 this.sortType = st[this.sortType];
12211 // set default sortType for strings and dates
12212 if(!this.sortType){
12215 this.sortType = st.asUCString;
12218 this.sortType = st.asDate;
12221 this.sortType = st.none;
12226 var stripRe = /[\$,%]/g;
12228 // prebuilt conversion function for this field, instead of
12229 // switching every time we're reading a value
12231 var cv, dateFormat = this.dateFormat;
12236 cv = function(v){ return v; };
12239 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12243 return v !== undefined && v !== null && v !== '' ?
12244 parseInt(String(v).replace(stripRe, ""), 10) : '';
12249 return v !== undefined && v !== null && v !== '' ?
12250 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12255 cv = function(v){ return v === true || v === "true" || v == 1; };
12262 if(v instanceof Date){
12266 if(dateFormat == "timestamp"){
12267 return new Date(v*1000);
12269 return Date.parseDate(v, dateFormat);
12271 var parsed = Date.parse(v);
12272 return parsed ? new Date(parsed) : null;
12281 Roo.data.Field.prototype = {
12289 * Ext JS Library 1.1.1
12290 * Copyright(c) 2006-2007, Ext JS, LLC.
12292 * Originally Released Under LGPL - original licence link has changed is not relivant.
12295 * <script type="text/javascript">
12298 // Base class for reading structured data from a data source. This class is intended to be
12299 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12302 * @class Roo.data.DataReader
12303 * Base class for reading structured data from a data source. This class is intended to be
12304 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12307 Roo.data.DataReader = function(meta, recordType){
12311 this.recordType = recordType instanceof Array ?
12312 Roo.data.Record.create(recordType) : recordType;
12315 Roo.data.DataReader.prototype = {
12317 * Create an empty record
12318 * @param {Object} data (optional) - overlay some values
12319 * @return {Roo.data.Record} record created.
12321 newRow : function(d) {
12323 this.recordType.prototype.fields.each(function(c) {
12325 case 'int' : da[c.name] = 0; break;
12326 case 'date' : da[c.name] = new Date(); break;
12327 case 'float' : da[c.name] = 0.0; break;
12328 case 'boolean' : da[c.name] = false; break;
12329 default : da[c.name] = ""; break;
12333 return new this.recordType(Roo.apply(da, d));
12338 * Ext JS Library 1.1.1
12339 * Copyright(c) 2006-2007, Ext JS, LLC.
12341 * Originally Released Under LGPL - original licence link has changed is not relivant.
12344 * <script type="text/javascript">
12348 * @class Roo.data.DataProxy
12349 * @extends Roo.data.Observable
12350 * This class is an abstract base class for implementations which provide retrieval of
12351 * unformatted data objects.<br>
12353 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12354 * (of the appropriate type which knows how to parse the data object) to provide a block of
12355 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12357 * Custom implementations must implement the load method as described in
12358 * {@link Roo.data.HttpProxy#load}.
12360 Roo.data.DataProxy = function(){
12363 * @event beforeload
12364 * Fires before a network request is made to retrieve a data object.
12365 * @param {Object} This DataProxy object.
12366 * @param {Object} params The params parameter to the load function.
12371 * Fires before the load method's callback is called.
12372 * @param {Object} This DataProxy object.
12373 * @param {Object} o The data object.
12374 * @param {Object} arg The callback argument object passed to the load function.
12378 * @event loadexception
12379 * Fires if an Exception occurs during data retrieval.
12380 * @param {Object} This DataProxy object.
12381 * @param {Object} o The data object.
12382 * @param {Object} arg The callback argument object passed to the load function.
12383 * @param {Object} e The Exception.
12385 loadexception : true
12387 Roo.data.DataProxy.superclass.constructor.call(this);
12390 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12393 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12397 * Ext JS Library 1.1.1
12398 * Copyright(c) 2006-2007, Ext JS, LLC.
12400 * Originally Released Under LGPL - original licence link has changed is not relivant.
12403 * <script type="text/javascript">
12406 * @class Roo.data.MemoryProxy
12407 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12408 * to the Reader when its load method is called.
12410 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12412 Roo.data.MemoryProxy = function(data){
12416 Roo.data.MemoryProxy.superclass.constructor.call(this);
12420 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12423 * Load data from the requested source (in this case an in-memory
12424 * data object passed to the constructor), read the data object into
12425 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12426 * process that block using the passed callback.
12427 * @param {Object} params This parameter is not used by the MemoryProxy class.
12428 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12429 * object into a block of Roo.data.Records.
12430 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12431 * The function must be passed <ul>
12432 * <li>The Record block object</li>
12433 * <li>The "arg" argument from the load function</li>
12434 * <li>A boolean success indicator</li>
12436 * @param {Object} scope The scope in which to call the callback
12437 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12439 load : function(params, reader, callback, scope, arg){
12440 params = params || {};
12443 result = reader.readRecords(params.data ? params.data :this.data);
12445 this.fireEvent("loadexception", this, arg, null, e);
12446 callback.call(scope, null, arg, false);
12449 callback.call(scope, result, arg, true);
12453 update : function(params, records){
12458 * Ext JS Library 1.1.1
12459 * Copyright(c) 2006-2007, Ext JS, LLC.
12461 * Originally Released Under LGPL - original licence link has changed is not relivant.
12464 * <script type="text/javascript">
12467 * @class Roo.data.HttpProxy
12468 * @extends Roo.data.DataProxy
12469 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12470 * configured to reference a certain URL.<br><br>
12472 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12473 * from which the running page was served.<br><br>
12475 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12477 * Be aware that to enable the browser to parse an XML document, the server must set
12478 * the Content-Type header in the HTTP response to "text/xml".
12480 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12481 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12482 * will be used to make the request.
12484 Roo.data.HttpProxy = function(conn){
12485 Roo.data.HttpProxy.superclass.constructor.call(this);
12486 // is conn a conn config or a real conn?
12488 this.useAjax = !conn || !conn.events;
12492 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12493 // thse are take from connection...
12496 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12499 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12500 * extra parameters to each request made by this object. (defaults to undefined)
12503 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12504 * to each request made by this object. (defaults to undefined)
12507 * @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)
12510 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12513 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12519 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12523 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12524 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12525 * a finer-grained basis than the DataProxy events.
12527 getConnection : function(){
12528 return this.useAjax ? Roo.Ajax : this.conn;
12532 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12533 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12534 * process that block using the passed callback.
12535 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12536 * for the request to the remote server.
12537 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12538 * object into a block of Roo.data.Records.
12539 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12540 * The function must be passed <ul>
12541 * <li>The Record block object</li>
12542 * <li>The "arg" argument from the load function</li>
12543 * <li>A boolean success indicator</li>
12545 * @param {Object} scope The scope in which to call the callback
12546 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12548 load : function(params, reader, callback, scope, arg){
12549 if(this.fireEvent("beforeload", this, params) !== false){
12551 params : params || {},
12553 callback : callback,
12558 callback : this.loadResponse,
12562 Roo.applyIf(o, this.conn);
12563 if(this.activeRequest){
12564 Roo.Ajax.abort(this.activeRequest);
12566 this.activeRequest = Roo.Ajax.request(o);
12568 this.conn.request(o);
12571 callback.call(scope||this, null, arg, false);
12576 loadResponse : function(o, success, response){
12577 delete this.activeRequest;
12579 this.fireEvent("loadexception", this, o, response);
12580 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12585 result = o.reader.read(response);
12587 this.fireEvent("loadexception", this, o, response, e);
12588 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12592 this.fireEvent("load", this, o, o.request.arg);
12593 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12597 update : function(dataSet){
12602 updateResponse : function(dataSet){
12607 * Ext JS Library 1.1.1
12608 * Copyright(c) 2006-2007, Ext JS, LLC.
12610 * Originally Released Under LGPL - original licence link has changed is not relivant.
12613 * <script type="text/javascript">
12617 * @class Roo.data.ScriptTagProxy
12618 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12619 * other than the originating domain of the running page.<br><br>
12621 * <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
12622 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12624 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12625 * source code that is used as the source inside a <script> tag.<br><br>
12627 * In order for the browser to process the returned data, the server must wrap the data object
12628 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12629 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12630 * depending on whether the callback name was passed:
12633 boolean scriptTag = false;
12634 String cb = request.getParameter("callback");
12637 response.setContentType("text/javascript");
12639 response.setContentType("application/x-json");
12641 Writer out = response.getWriter();
12643 out.write(cb + "(");
12645 out.print(dataBlock.toJsonString());
12652 * @param {Object} config A configuration object.
12654 Roo.data.ScriptTagProxy = function(config){
12655 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12656 Roo.apply(this, config);
12657 this.head = document.getElementsByTagName("head")[0];
12660 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12662 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12664 * @cfg {String} url The URL from which to request the data object.
12667 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12671 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12672 * the server the name of the callback function set up by the load call to process the returned data object.
12673 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12674 * javascript output which calls this named function passing the data object as its only parameter.
12676 callbackParam : "callback",
12678 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12679 * name to the request.
12684 * Load data from the configured URL, read the data object into
12685 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12686 * process that block using the passed callback.
12687 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12688 * for the request to the remote server.
12689 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12690 * object into a block of Roo.data.Records.
12691 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12692 * The function must be passed <ul>
12693 * <li>The Record block object</li>
12694 * <li>The "arg" argument from the load function</li>
12695 * <li>A boolean success indicator</li>
12697 * @param {Object} scope The scope in which to call the callback
12698 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12700 load : function(params, reader, callback, scope, arg){
12701 if(this.fireEvent("beforeload", this, params) !== false){
12703 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12705 var url = this.url;
12706 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12708 url += "&_dc=" + (new Date().getTime());
12710 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12713 cb : "stcCallback"+transId,
12714 scriptId : "stcScript"+transId,
12718 callback : callback,
12724 window[trans.cb] = function(o){
12725 conn.handleResponse(o, trans);
12728 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12730 if(this.autoAbort !== false){
12734 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12736 var script = document.createElement("script");
12737 script.setAttribute("src", url);
12738 script.setAttribute("type", "text/javascript");
12739 script.setAttribute("id", trans.scriptId);
12740 this.head.appendChild(script);
12742 this.trans = trans;
12744 callback.call(scope||this, null, arg, false);
12749 isLoading : function(){
12750 return this.trans ? true : false;
12754 * Abort the current server request.
12756 abort : function(){
12757 if(this.isLoading()){
12758 this.destroyTrans(this.trans);
12763 destroyTrans : function(trans, isLoaded){
12764 this.head.removeChild(document.getElementById(trans.scriptId));
12765 clearTimeout(trans.timeoutId);
12767 window[trans.cb] = undefined;
12769 delete window[trans.cb];
12772 // if hasn't been loaded, wait for load to remove it to prevent script error
12773 window[trans.cb] = function(){
12774 window[trans.cb] = undefined;
12776 delete window[trans.cb];
12783 handleResponse : function(o, trans){
12784 this.trans = false;
12785 this.destroyTrans(trans, true);
12788 result = trans.reader.readRecords(o);
12790 this.fireEvent("loadexception", this, o, trans.arg, e);
12791 trans.callback.call(trans.scope||window, null, trans.arg, false);
12794 this.fireEvent("load", this, o, trans.arg);
12795 trans.callback.call(trans.scope||window, result, trans.arg, true);
12799 handleFailure : function(trans){
12800 this.trans = false;
12801 this.destroyTrans(trans, false);
12802 this.fireEvent("loadexception", this, null, trans.arg);
12803 trans.callback.call(trans.scope||window, null, trans.arg, false);
12807 * Ext JS Library 1.1.1
12808 * Copyright(c) 2006-2007, Ext JS, LLC.
12810 * Originally Released Under LGPL - original licence link has changed is not relivant.
12813 * <script type="text/javascript">
12817 * @class Roo.data.JsonReader
12818 * @extends Roo.data.DataReader
12819 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12820 * based on mappings in a provided Roo.data.Record constructor.
12822 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12823 * in the reply previously.
12828 var RecordDef = Roo.data.Record.create([
12829 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12830 {name: 'occupation'} // This field will use "occupation" as the mapping.
12832 var myReader = new Roo.data.JsonReader({
12833 totalProperty: "results", // The property which contains the total dataset size (optional)
12834 root: "rows", // The property which contains an Array of row objects
12835 id: "id" // The property within each row object that provides an ID for the record (optional)
12839 * This would consume a JSON file like this:
12841 { 'results': 2, 'rows': [
12842 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12843 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12846 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12847 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12848 * paged from the remote server.
12849 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12850 * @cfg {String} root name of the property which contains the Array of row objects.
12851 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12852 * @cfg {Array} fields Array of field definition objects
12854 * Create a new JsonReader
12855 * @param {Object} meta Metadata configuration options
12856 * @param {Object} recordType Either an Array of field definition objects,
12857 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12859 Roo.data.JsonReader = function(meta, recordType){
12862 // set some defaults:
12863 Roo.applyIf(meta, {
12864 totalProperty: 'total',
12865 successProperty : 'success',
12870 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12872 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12875 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12876 * Used by Store query builder to append _requestMeta to params.
12879 metaFromRemote : false,
12881 * This method is only used by a DataProxy which has retrieved data from a remote server.
12882 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12883 * @return {Object} data A data block which is used by an Roo.data.Store object as
12884 * a cache of Roo.data.Records.
12886 read : function(response){
12887 var json = response.responseText;
12889 var o = /* eval:var:o */ eval("("+json+")");
12891 throw {message: "JsonReader.read: Json object not found"};
12897 this.metaFromRemote = true;
12898 this.meta = o.metaData;
12899 this.recordType = Roo.data.Record.create(o.metaData.fields);
12900 this.onMetaChange(this.meta, this.recordType, o);
12902 return this.readRecords(o);
12905 // private function a store will implement
12906 onMetaChange : function(meta, recordType, o){
12913 simpleAccess: function(obj, subsc) {
12920 getJsonAccessor: function(){
12922 return function(expr) {
12924 return(re.test(expr))
12925 ? new Function("obj", "return obj." + expr)
12930 return Roo.emptyFn;
12935 * Create a data block containing Roo.data.Records from an XML document.
12936 * @param {Object} o An object which contains an Array of row objects in the property specified
12937 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12938 * which contains the total size of the dataset.
12939 * @return {Object} data A data block which is used by an Roo.data.Store object as
12940 * a cache of Roo.data.Records.
12942 readRecords : function(o){
12944 * After any data loads, the raw JSON data is available for further custom processing.
12948 var s = this.meta, Record = this.recordType,
12949 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12951 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12953 if(s.totalProperty) {
12954 this.getTotal = this.getJsonAccessor(s.totalProperty);
12956 if(s.successProperty) {
12957 this.getSuccess = this.getJsonAccessor(s.successProperty);
12959 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12961 var g = this.getJsonAccessor(s.id);
12962 this.getId = function(rec) {
12964 return (r === undefined || r === "") ? null : r;
12967 this.getId = function(){return null;};
12970 for(var jj = 0; jj < fl; jj++){
12972 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12973 this.ef[jj] = this.getJsonAccessor(map);
12977 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12978 if(s.totalProperty){
12979 var vt = parseInt(this.getTotal(o), 10);
12984 if(s.successProperty){
12985 var vs = this.getSuccess(o);
12986 if(vs === false || vs === 'false'){
12991 for(var i = 0; i < c; i++){
12994 var id = this.getId(n);
12995 for(var j = 0; j < fl; j++){
12997 var v = this.ef[j](n);
12999 Roo.log('missing convert for ' + f.name);
13003 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13005 var record = new Record(values, id);
13007 records[i] = record;
13013 totalRecords : totalRecords
13018 * Ext JS Library 1.1.1
13019 * Copyright(c) 2006-2007, Ext JS, LLC.
13021 * Originally Released Under LGPL - original licence link has changed is not relivant.
13024 * <script type="text/javascript">
13028 * @class Roo.data.ArrayReader
13029 * @extends Roo.data.DataReader
13030 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13031 * Each element of that Array represents a row of data fields. The
13032 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13033 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13037 var RecordDef = Roo.data.Record.create([
13038 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13039 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13041 var myReader = new Roo.data.ArrayReader({
13042 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13046 * This would consume an Array like this:
13048 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13052 * Create a new JsonReader
13053 * @param {Object} meta Metadata configuration options.
13054 * @param {Object|Array} recordType Either an Array of field definition objects
13056 * @cfg {Array} fields Array of field definition objects
13057 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13058 * as specified to {@link Roo.data.Record#create},
13059 * or an {@link Roo.data.Record} object
13062 * created using {@link Roo.data.Record#create}.
13064 Roo.data.ArrayReader = function(meta, recordType){
13067 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13070 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13072 * Create a data block containing Roo.data.Records from an XML document.
13073 * @param {Object} o An Array of row objects which represents the dataset.
13074 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13075 * a cache of Roo.data.Records.
13077 readRecords : function(o)
13079 var sid = this.meta ? this.meta.id : null;
13080 var recordType = this.recordType, fields = recordType.prototype.fields;
13083 for(var i = 0; i < root.length; i++){
13086 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13087 for(var j = 0, jlen = fields.length; j < jlen; j++){
13088 var f = fields.items[j];
13089 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13090 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13092 values[f.name] = v;
13094 var record = new recordType(values, id);
13096 records[records.length] = record;
13100 totalRecords : records.length
13109 * @class Roo.bootstrap.ComboBox
13110 * @extends Roo.bootstrap.TriggerField
13111 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13112 * @cfg {Boolean} append (true|false) default false
13113 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13114 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13115 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13116 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13117 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13118 * @cfg {Boolean} animate default true
13119 * @cfg {Boolean} emptyResultText only for touch device
13120 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13121 * @cfg {String} emptyTitle default ''
13123 * Create a new ComboBox.
13124 * @param {Object} config Configuration options
13126 Roo.bootstrap.ComboBox = function(config){
13127 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13131 * Fires when the dropdown list is expanded
13132 * @param {Roo.bootstrap.ComboBox} combo This combo box
13137 * Fires when the dropdown list is collapsed
13138 * @param {Roo.bootstrap.ComboBox} combo This combo box
13142 * @event beforeselect
13143 * Fires before a list item is selected. Return false to cancel the selection.
13144 * @param {Roo.bootstrap.ComboBox} combo This combo box
13145 * @param {Roo.data.Record} record The data record returned from the underlying store
13146 * @param {Number} index The index of the selected item in the dropdown list
13148 'beforeselect' : true,
13151 * Fires when a list item is selected
13152 * @param {Roo.bootstrap.ComboBox} combo This combo box
13153 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13154 * @param {Number} index The index of the selected item in the dropdown list
13158 * @event beforequery
13159 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13160 * The event object passed has these properties:
13161 * @param {Roo.bootstrap.ComboBox} combo This combo box
13162 * @param {String} query The query
13163 * @param {Boolean} forceAll true to force "all" query
13164 * @param {Boolean} cancel true to cancel the query
13165 * @param {Object} e The query event object
13167 'beforequery': true,
13170 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13171 * @param {Roo.bootstrap.ComboBox} combo This combo box
13176 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13177 * @param {Roo.bootstrap.ComboBox} combo This combo box
13178 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13183 * Fires when the remove value from the combobox array
13184 * @param {Roo.bootstrap.ComboBox} combo This combo box
13188 * @event afterremove
13189 * Fires when the remove value from the combobox array
13190 * @param {Roo.bootstrap.ComboBox} combo This combo box
13192 'afterremove' : true,
13194 * @event specialfilter
13195 * Fires when specialfilter
13196 * @param {Roo.bootstrap.ComboBox} combo This combo box
13198 'specialfilter' : true,
13201 * Fires when tick the element
13202 * @param {Roo.bootstrap.ComboBox} combo This combo box
13206 * @event touchviewdisplay
13207 * Fires when touch view require special display (default is using displayField)
13208 * @param {Roo.bootstrap.ComboBox} combo This combo box
13209 * @param {Object} cfg set html .
13211 'touchviewdisplay' : true
13216 this.tickItems = [];
13218 this.selectedIndex = -1;
13219 if(this.mode == 'local'){
13220 if(config.queryDelay === undefined){
13221 this.queryDelay = 10;
13223 if(config.minChars === undefined){
13229 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13232 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13233 * rendering into an Roo.Editor, defaults to false)
13236 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13237 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13240 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13243 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13244 * the dropdown list (defaults to undefined, with no header element)
13248 * @cfg {String/Roo.Template} tpl The template to use to render the output
13252 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13254 listWidth: undefined,
13256 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13257 * mode = 'remote' or 'text' if mode = 'local')
13259 displayField: undefined,
13262 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13263 * mode = 'remote' or 'value' if mode = 'local').
13264 * Note: use of a valueField requires the user make a selection
13265 * in order for a value to be mapped.
13267 valueField: undefined,
13269 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13274 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13275 * field's data value (defaults to the underlying DOM element's name)
13277 hiddenName: undefined,
13279 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13283 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13285 selectedClass: 'active',
13288 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13292 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13293 * anchor positions (defaults to 'tl-bl')
13295 listAlign: 'tl-bl?',
13297 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13301 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13302 * query specified by the allQuery config option (defaults to 'query')
13304 triggerAction: 'query',
13306 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13307 * (defaults to 4, does not apply if editable = false)
13311 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13312 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13316 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13317 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13321 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13322 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13326 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13327 * when editable = true (defaults to false)
13329 selectOnFocus:false,
13331 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13333 queryParam: 'query',
13335 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13336 * when mode = 'remote' (defaults to 'Loading...')
13338 loadingText: 'Loading...',
13340 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13344 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13348 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13349 * traditional select (defaults to true)
13353 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13357 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13361 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13362 * listWidth has a higher value)
13366 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13367 * allow the user to set arbitrary text into the field (defaults to false)
13369 forceSelection:false,
13371 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13372 * if typeAhead = true (defaults to 250)
13374 typeAheadDelay : 250,
13376 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13377 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13379 valueNotFoundText : undefined,
13381 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13383 blockFocus : false,
13386 * @cfg {Boolean} disableClear Disable showing of clear button.
13388 disableClear : false,
13390 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13392 alwaysQuery : false,
13395 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13400 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13402 invalidClass : "has-warning",
13405 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13407 validClass : "has-success",
13410 * @cfg {Boolean} specialFilter (true|false) special filter default false
13412 specialFilter : false,
13415 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13417 mobileTouchView : true,
13420 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13422 useNativeIOS : false,
13425 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13427 mobile_restrict_height : false,
13429 ios_options : false,
13441 btnPosition : 'right',
13442 triggerList : true,
13443 showToggleBtn : true,
13445 emptyResultText: 'Empty',
13446 triggerText : 'Select',
13449 // element that contains real text value.. (when hidden is used..)
13451 getAutoCreate : function()
13456 * Render classic select for iso
13459 if(Roo.isIOS && this.useNativeIOS){
13460 cfg = this.getAutoCreateNativeIOS();
13468 if(Roo.isTouch && this.mobileTouchView){
13469 cfg = this.getAutoCreateTouchView();
13476 if(!this.tickable){
13477 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13482 * ComboBox with tickable selections
13485 var align = this.labelAlign || this.parentLabelAlign();
13488 cls : 'form-group roo-combobox-tickable' //input-group
13491 var btn_text_select = '';
13492 var btn_text_done = '';
13493 var btn_text_cancel = '';
13495 if (this.btn_text_show) {
13496 btn_text_select = 'Select';
13497 btn_text_done = 'Done';
13498 btn_text_cancel = 'Cancel';
13503 cls : 'tickable-buttons',
13508 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13509 //html : this.triggerText
13510 html: btn_text_select
13516 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13518 html: btn_text_done
13524 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13526 html: btn_text_cancel
13532 buttons.cn.unshift({
13534 cls: 'roo-select2-search-field-input'
13540 Roo.each(buttons.cn, function(c){
13542 c.cls += ' btn-' + _this.size;
13545 if (_this.disabled) {
13552 style : 'display: contents',
13557 cls: 'form-hidden-field'
13561 cls: 'roo-select2-choices',
13565 cls: 'roo-select2-search-field',
13576 cls: 'roo-select2-container input-group roo-select2-container-multi',
13582 // cls: 'typeahead typeahead-long dropdown-menu',
13583 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13588 if(this.hasFeedback && !this.allowBlank){
13592 cls: 'glyphicon form-control-feedback'
13595 combobox.cn.push(feedback);
13600 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13601 tooltip : 'This field is required'
13603 if (Roo.bootstrap.version == 4) {
13606 style : 'display:none'
13609 if (align ==='left' && this.fieldLabel.length) {
13611 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13618 cls : 'control-label col-form-label',
13619 html : this.fieldLabel
13631 var labelCfg = cfg.cn[1];
13632 var contentCfg = cfg.cn[2];
13635 if(this.indicatorpos == 'right'){
13641 cls : 'control-label col-form-label',
13645 html : this.fieldLabel
13661 labelCfg = cfg.cn[0];
13662 contentCfg = cfg.cn[1];
13666 if(this.labelWidth > 12){
13667 labelCfg.style = "width: " + this.labelWidth + 'px';
13670 if(this.labelWidth < 13 && this.labelmd == 0){
13671 this.labelmd = this.labelWidth;
13674 if(this.labellg > 0){
13675 labelCfg.cls += ' col-lg-' + this.labellg;
13676 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13679 if(this.labelmd > 0){
13680 labelCfg.cls += ' col-md-' + this.labelmd;
13681 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13684 if(this.labelsm > 0){
13685 labelCfg.cls += ' col-sm-' + this.labelsm;
13686 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13689 if(this.labelxs > 0){
13690 labelCfg.cls += ' col-xs-' + this.labelxs;
13691 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13695 } else if ( this.fieldLabel.length) {
13696 // Roo.log(" label");
13701 //cls : 'input-group-addon',
13702 html : this.fieldLabel
13707 if(this.indicatorpos == 'right'){
13711 //cls : 'input-group-addon',
13712 html : this.fieldLabel
13722 // Roo.log(" no label && no align");
13729 ['xs','sm','md','lg'].map(function(size){
13730 if (settings[size]) {
13731 cfg.cls += ' col-' + size + '-' + settings[size];
13739 _initEventsCalled : false,
13742 initEvents: function()
13744 if (this._initEventsCalled) { // as we call render... prevent looping...
13747 this._initEventsCalled = true;
13750 throw "can not find store for combo";
13753 this.indicator = this.indicatorEl();
13755 this.store = Roo.factory(this.store, Roo.data);
13756 this.store.parent = this;
13758 // if we are building from html. then this element is so complex, that we can not really
13759 // use the rendered HTML.
13760 // so we have to trash and replace the previous code.
13761 if (Roo.XComponent.build_from_html) {
13762 // remove this element....
13763 var e = this.el.dom, k=0;
13764 while (e ) { e = e.previousSibling; ++k;}
13769 this.rendered = false;
13771 this.render(this.parent().getChildContainer(true), k);
13774 if(Roo.isIOS && this.useNativeIOS){
13775 this.initIOSView();
13783 if(Roo.isTouch && this.mobileTouchView){
13784 this.initTouchView();
13789 this.initTickableEvents();
13793 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13795 if(this.hiddenName){
13797 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13799 this.hiddenField.dom.value =
13800 this.hiddenValue !== undefined ? this.hiddenValue :
13801 this.value !== undefined ? this.value : '';
13803 // prevent input submission
13804 this.el.dom.removeAttribute('name');
13805 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13810 // this.el.dom.setAttribute('autocomplete', 'off');
13813 var cls = 'x-combo-list';
13815 //this.list = new Roo.Layer({
13816 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13822 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13823 _this.list.setWidth(lw);
13826 this.list.on('mouseover', this.onViewOver, this);
13827 this.list.on('mousemove', this.onViewMove, this);
13828 this.list.on('scroll', this.onViewScroll, this);
13831 this.list.swallowEvent('mousewheel');
13832 this.assetHeight = 0;
13835 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13836 this.assetHeight += this.header.getHeight();
13839 this.innerList = this.list.createChild({cls:cls+'-inner'});
13840 this.innerList.on('mouseover', this.onViewOver, this);
13841 this.innerList.on('mousemove', this.onViewMove, this);
13842 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13844 if(this.allowBlank && !this.pageSize && !this.disableClear){
13845 this.footer = this.list.createChild({cls:cls+'-ft'});
13846 this.pageTb = new Roo.Toolbar(this.footer);
13850 this.footer = this.list.createChild({cls:cls+'-ft'});
13851 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13852 {pageSize: this.pageSize});
13856 if (this.pageTb && this.allowBlank && !this.disableClear) {
13858 this.pageTb.add(new Roo.Toolbar.Fill(), {
13859 cls: 'x-btn-icon x-btn-clear',
13861 handler: function()
13864 _this.clearValue();
13865 _this.onSelect(false, -1);
13870 this.assetHeight += this.footer.getHeight();
13875 this.tpl = Roo.bootstrap.version == 4 ?
13876 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13877 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13880 this.view = new Roo.View(this.list, this.tpl, {
13881 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13883 //this.view.wrapEl.setDisplayed(false);
13884 this.view.on('click', this.onViewClick, this);
13887 this.store.on('beforeload', this.onBeforeLoad, this);
13888 this.store.on('load', this.onLoad, this);
13889 this.store.on('loadexception', this.onLoadException, this);
13891 if(this.resizable){
13892 this.resizer = new Roo.Resizable(this.list, {
13893 pinned:true, handles:'se'
13895 this.resizer.on('resize', function(r, w, h){
13896 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13897 this.listWidth = w;
13898 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13899 this.restrictHeight();
13901 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13904 if(!this.editable){
13905 this.editable = true;
13906 this.setEditable(false);
13911 if (typeof(this.events.add.listeners) != 'undefined') {
13913 this.addicon = this.wrap.createChild(
13914 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13916 this.addicon.on('click', function(e) {
13917 this.fireEvent('add', this);
13920 if (typeof(this.events.edit.listeners) != 'undefined') {
13922 this.editicon = this.wrap.createChild(
13923 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13924 if (this.addicon) {
13925 this.editicon.setStyle('margin-left', '40px');
13927 this.editicon.on('click', function(e) {
13929 // we fire even if inothing is selected..
13930 this.fireEvent('edit', this, this.lastData );
13936 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13937 "up" : function(e){
13938 this.inKeyMode = true;
13942 "down" : function(e){
13943 if(!this.isExpanded()){
13944 this.onTriggerClick();
13946 this.inKeyMode = true;
13951 "enter" : function(e){
13952 // this.onViewClick();
13956 if(this.fireEvent("specialkey", this, e)){
13957 this.onViewClick(false);
13963 "esc" : function(e){
13967 "tab" : function(e){
13970 if(this.fireEvent("specialkey", this, e)){
13971 this.onViewClick(false);
13979 doRelay : function(foo, bar, hname){
13980 if(hname == 'down' || this.scope.isExpanded()){
13981 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13990 this.queryDelay = Math.max(this.queryDelay || 10,
13991 this.mode == 'local' ? 10 : 250);
13994 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13996 if(this.typeAhead){
13997 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13999 if(this.editable !== false){
14000 this.inputEl().on("keyup", this.onKeyUp, this);
14002 if(this.forceSelection){
14003 this.inputEl().on('blur', this.doForce, this);
14007 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14008 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14012 initTickableEvents: function()
14016 if(this.hiddenName){
14018 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14020 this.hiddenField.dom.value =
14021 this.hiddenValue !== undefined ? this.hiddenValue :
14022 this.value !== undefined ? this.value : '';
14024 // prevent input submission
14025 this.el.dom.removeAttribute('name');
14026 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14031 // this.list = this.el.select('ul.dropdown-menu',true).first();
14033 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14034 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14035 if(this.triggerList){
14036 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14039 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14040 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14042 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14043 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14045 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14046 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14048 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14049 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14050 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14053 this.cancelBtn.hide();
14058 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14059 _this.list.setWidth(lw);
14062 this.list.on('mouseover', this.onViewOver, this);
14063 this.list.on('mousemove', this.onViewMove, this);
14065 this.list.on('scroll', this.onViewScroll, this);
14068 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14069 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14072 this.view = new Roo.View(this.list, this.tpl, {
14077 selectedClass: this.selectedClass
14080 //this.view.wrapEl.setDisplayed(false);
14081 this.view.on('click', this.onViewClick, this);
14085 this.store.on('beforeload', this.onBeforeLoad, this);
14086 this.store.on('load', this.onLoad, this);
14087 this.store.on('loadexception', this.onLoadException, this);
14090 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14091 "up" : function(e){
14092 this.inKeyMode = true;
14096 "down" : function(e){
14097 this.inKeyMode = true;
14101 "enter" : function(e){
14102 if(this.fireEvent("specialkey", this, e)){
14103 this.onViewClick(false);
14109 "esc" : function(e){
14110 this.onTickableFooterButtonClick(e, false, false);
14113 "tab" : function(e){
14114 this.fireEvent("specialkey", this, e);
14116 this.onTickableFooterButtonClick(e, false, false);
14123 doRelay : function(e, fn, key){
14124 if(this.scope.isExpanded()){
14125 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14134 this.queryDelay = Math.max(this.queryDelay || 10,
14135 this.mode == 'local' ? 10 : 250);
14138 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14140 if(this.typeAhead){
14141 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14144 if(this.editable !== false){
14145 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14148 this.indicator = this.indicatorEl();
14150 if(this.indicator){
14151 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14152 this.indicator.hide();
14157 onDestroy : function(){
14159 this.view.setStore(null);
14160 this.view.el.removeAllListeners();
14161 this.view.el.remove();
14162 this.view.purgeListeners();
14165 this.list.dom.innerHTML = '';
14169 this.store.un('beforeload', this.onBeforeLoad, this);
14170 this.store.un('load', this.onLoad, this);
14171 this.store.un('loadexception', this.onLoadException, this);
14173 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14177 fireKey : function(e){
14178 if(e.isNavKeyPress() && !this.list.isVisible()){
14179 this.fireEvent("specialkey", this, e);
14184 onResize: function(w, h){
14185 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14187 // if(typeof w != 'number'){
14188 // // we do not handle it!?!?
14191 // var tw = this.trigger.getWidth();
14192 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14193 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14195 // this.inputEl().setWidth( this.adjustWidth('input', x));
14197 // //this.trigger.setStyle('left', x+'px');
14199 // if(this.list && this.listWidth === undefined){
14200 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14201 // this.list.setWidth(lw);
14202 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14210 * Allow or prevent the user from directly editing the field text. If false is passed,
14211 * the user will only be able to select from the items defined in the dropdown list. This method
14212 * is the runtime equivalent of setting the 'editable' config option at config time.
14213 * @param {Boolean} value True to allow the user to directly edit the field text
14215 setEditable : function(value){
14216 if(value == this.editable){
14219 this.editable = value;
14221 this.inputEl().dom.setAttribute('readOnly', true);
14222 this.inputEl().on('mousedown', this.onTriggerClick, this);
14223 this.inputEl().addClass('x-combo-noedit');
14225 this.inputEl().dom.setAttribute('readOnly', false);
14226 this.inputEl().un('mousedown', this.onTriggerClick, this);
14227 this.inputEl().removeClass('x-combo-noedit');
14233 onBeforeLoad : function(combo,opts){
14234 if(!this.hasFocus){
14238 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14240 this.restrictHeight();
14241 this.selectedIndex = -1;
14245 onLoad : function(){
14247 this.hasQuery = false;
14249 if(!this.hasFocus){
14253 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14254 this.loading.hide();
14257 if(this.store.getCount() > 0){
14260 this.restrictHeight();
14261 if(this.lastQuery == this.allQuery){
14262 if(this.editable && !this.tickable){
14263 this.inputEl().dom.select();
14267 !this.selectByValue(this.value, true) &&
14270 !this.store.lastOptions ||
14271 typeof(this.store.lastOptions.add) == 'undefined' ||
14272 this.store.lastOptions.add != true
14275 this.select(0, true);
14278 if(this.autoFocus){
14281 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14282 this.taTask.delay(this.typeAheadDelay);
14286 this.onEmptyResults();
14292 onLoadException : function()
14294 this.hasQuery = false;
14296 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14297 this.loading.hide();
14300 if(this.tickable && this.editable){
14305 // only causes errors at present
14306 //Roo.log(this.store.reader.jsonData);
14307 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14309 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14315 onTypeAhead : function(){
14316 if(this.store.getCount() > 0){
14317 var r = this.store.getAt(0);
14318 var newValue = r.data[this.displayField];
14319 var len = newValue.length;
14320 var selStart = this.getRawValue().length;
14322 if(selStart != len){
14323 this.setRawValue(newValue);
14324 this.selectText(selStart, newValue.length);
14330 onSelect : function(record, index){
14332 if(this.fireEvent('beforeselect', this, record, index) !== false){
14334 this.setFromData(index > -1 ? record.data : false);
14337 this.fireEvent('select', this, record, index);
14342 * Returns the currently selected field value or empty string if no value is set.
14343 * @return {String} value The selected value
14345 getValue : function()
14347 if(Roo.isIOS && this.useNativeIOS){
14348 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14352 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14355 if(this.valueField){
14356 return typeof this.value != 'undefined' ? this.value : '';
14358 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14362 getRawValue : function()
14364 if(Roo.isIOS && this.useNativeIOS){
14365 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14368 var v = this.inputEl().getValue();
14374 * Clears any text/value currently set in the field
14376 clearValue : function(){
14378 if(this.hiddenField){
14379 this.hiddenField.dom.value = '';
14382 this.setRawValue('');
14383 this.lastSelectionText = '';
14384 this.lastData = false;
14386 var close = this.closeTriggerEl();
14397 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14398 * will be displayed in the field. If the value does not match the data value of an existing item,
14399 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14400 * Otherwise the field will be blank (although the value will still be set).
14401 * @param {String} value The value to match
14403 setValue : function(v)
14405 if(Roo.isIOS && this.useNativeIOS){
14406 this.setIOSValue(v);
14416 if(this.valueField){
14417 var r = this.findRecord(this.valueField, v);
14419 text = r.data[this.displayField];
14420 }else if(this.valueNotFoundText !== undefined){
14421 text = this.valueNotFoundText;
14424 this.lastSelectionText = text;
14425 if(this.hiddenField){
14426 this.hiddenField.dom.value = v;
14428 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14431 var close = this.closeTriggerEl();
14434 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14440 * @property {Object} the last set data for the element
14445 * Sets the value of the field based on a object which is related to the record format for the store.
14446 * @param {Object} value the value to set as. or false on reset?
14448 setFromData : function(o){
14455 var dv = ''; // display value
14456 var vv = ''; // value value..
14458 if (this.displayField) {
14459 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14461 // this is an error condition!!!
14462 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14465 if(this.valueField){
14466 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14469 var close = this.closeTriggerEl();
14472 if(dv.length || vv * 1 > 0){
14474 this.blockFocus=true;
14480 if(this.hiddenField){
14481 this.hiddenField.dom.value = vv;
14483 this.lastSelectionText = dv;
14484 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14488 // no hidden field.. - we store the value in 'value', but still display
14489 // display field!!!!
14490 this.lastSelectionText = dv;
14491 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14498 reset : function(){
14499 // overridden so that last data is reset..
14506 this.setValue(this.originalValue);
14507 //this.clearInvalid();
14508 this.lastData = false;
14510 this.view.clearSelections();
14516 findRecord : function(prop, value){
14518 if(this.store.getCount() > 0){
14519 this.store.each(function(r){
14520 if(r.data[prop] == value){
14530 getName: function()
14532 // returns hidden if it's set..
14533 if (!this.rendered) {return ''};
14534 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14538 onViewMove : function(e, t){
14539 this.inKeyMode = false;
14543 onViewOver : function(e, t){
14544 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14547 var item = this.view.findItemFromChild(t);
14550 var index = this.view.indexOf(item);
14551 this.select(index, false);
14556 onViewClick : function(view, doFocus, el, e)
14558 var index = this.view.getSelectedIndexes()[0];
14560 var r = this.store.getAt(index);
14564 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14571 Roo.each(this.tickItems, function(v,k){
14573 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14575 _this.tickItems.splice(k, 1);
14577 if(typeof(e) == 'undefined' && view == false){
14578 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14590 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14591 this.tickItems.push(r.data);
14594 if(typeof(e) == 'undefined' && view == false){
14595 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14602 this.onSelect(r, index);
14604 if(doFocus !== false && !this.blockFocus){
14605 this.inputEl().focus();
14610 restrictHeight : function(){
14611 //this.innerList.dom.style.height = '';
14612 //var inner = this.innerList.dom;
14613 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14614 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14615 //this.list.beginUpdate();
14616 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14617 this.list.alignTo(this.inputEl(), this.listAlign);
14618 this.list.alignTo(this.inputEl(), this.listAlign);
14619 //this.list.endUpdate();
14623 onEmptyResults : function(){
14625 if(this.tickable && this.editable){
14626 this.hasFocus = false;
14627 this.restrictHeight();
14635 * Returns true if the dropdown list is expanded, else false.
14637 isExpanded : function(){
14638 return this.list.isVisible();
14642 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14643 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14644 * @param {String} value The data value of the item to select
14645 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14646 * selected item if it is not currently in view (defaults to true)
14647 * @return {Boolean} True if the value matched an item in the list, else false
14649 selectByValue : function(v, scrollIntoView){
14650 if(v !== undefined && v !== null){
14651 var r = this.findRecord(this.valueField || this.displayField, v);
14653 this.select(this.store.indexOf(r), scrollIntoView);
14661 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14662 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14663 * @param {Number} index The zero-based index of the list item to select
14664 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14665 * selected item if it is not currently in view (defaults to true)
14667 select : function(index, scrollIntoView){
14668 this.selectedIndex = index;
14669 this.view.select(index);
14670 if(scrollIntoView !== false){
14671 var el = this.view.getNode(index);
14673 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14676 this.list.scrollChildIntoView(el, false);
14682 selectNext : function(){
14683 var ct = this.store.getCount();
14685 if(this.selectedIndex == -1){
14687 }else if(this.selectedIndex < ct-1){
14688 this.select(this.selectedIndex+1);
14694 selectPrev : function(){
14695 var ct = this.store.getCount();
14697 if(this.selectedIndex == -1){
14699 }else if(this.selectedIndex != 0){
14700 this.select(this.selectedIndex-1);
14706 onKeyUp : function(e){
14707 if(this.editable !== false && !e.isSpecialKey()){
14708 this.lastKey = e.getKey();
14709 this.dqTask.delay(this.queryDelay);
14714 validateBlur : function(){
14715 return !this.list || !this.list.isVisible();
14719 initQuery : function(){
14721 var v = this.getRawValue();
14723 if(this.tickable && this.editable){
14724 v = this.tickableInputEl().getValue();
14731 doForce : function(){
14732 if(this.inputEl().dom.value.length > 0){
14733 this.inputEl().dom.value =
14734 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14740 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14741 * query allowing the query action to be canceled if needed.
14742 * @param {String} query The SQL query to execute
14743 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14744 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14745 * saved in the current store (defaults to false)
14747 doQuery : function(q, forceAll){
14749 if(q === undefined || q === null){
14754 forceAll: forceAll,
14758 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14763 forceAll = qe.forceAll;
14764 if(forceAll === true || (q.length >= this.minChars)){
14766 this.hasQuery = true;
14768 if(this.lastQuery != q || this.alwaysQuery){
14769 this.lastQuery = q;
14770 if(this.mode == 'local'){
14771 this.selectedIndex = -1;
14773 this.store.clearFilter();
14776 if(this.specialFilter){
14777 this.fireEvent('specialfilter', this);
14782 this.store.filter(this.displayField, q);
14785 this.store.fireEvent("datachanged", this.store);
14792 this.store.baseParams[this.queryParam] = q;
14794 var options = {params : this.getParams(q)};
14797 options.add = true;
14798 options.params.start = this.page * this.pageSize;
14801 this.store.load(options);
14804 * this code will make the page width larger, at the beginning, the list not align correctly,
14805 * we should expand the list on onLoad
14806 * so command out it
14811 this.selectedIndex = -1;
14816 this.loadNext = false;
14820 getParams : function(q){
14822 //p[this.queryParam] = q;
14826 p.limit = this.pageSize;
14832 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14834 collapse : function(){
14835 if(!this.isExpanded()){
14841 this.hasFocus = false;
14845 this.cancelBtn.hide();
14846 this.trigger.show();
14849 this.tickableInputEl().dom.value = '';
14850 this.tickableInputEl().blur();
14855 Roo.get(document).un('mousedown', this.collapseIf, this);
14856 Roo.get(document).un('mousewheel', this.collapseIf, this);
14857 if (!this.editable) {
14858 Roo.get(document).un('keydown', this.listKeyPress, this);
14860 this.fireEvent('collapse', this);
14866 collapseIf : function(e){
14867 var in_combo = e.within(this.el);
14868 var in_list = e.within(this.list);
14869 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14871 if (in_combo || in_list || is_list) {
14872 //e.stopPropagation();
14877 this.onTickableFooterButtonClick(e, false, false);
14885 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14887 expand : function(){
14889 if(this.isExpanded() || !this.hasFocus){
14893 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14894 this.list.setWidth(lw);
14900 this.restrictHeight();
14904 this.tickItems = Roo.apply([], this.item);
14907 this.cancelBtn.show();
14908 this.trigger.hide();
14911 this.tickableInputEl().focus();
14916 Roo.get(document).on('mousedown', this.collapseIf, this);
14917 Roo.get(document).on('mousewheel', this.collapseIf, this);
14918 if (!this.editable) {
14919 Roo.get(document).on('keydown', this.listKeyPress, this);
14922 this.fireEvent('expand', this);
14926 // Implements the default empty TriggerField.onTriggerClick function
14927 onTriggerClick : function(e)
14929 Roo.log('trigger click');
14931 if(this.disabled || !this.triggerList){
14936 this.loadNext = false;
14938 if(this.isExpanded()){
14940 if (!this.blockFocus) {
14941 this.inputEl().focus();
14945 this.hasFocus = true;
14946 if(this.triggerAction == 'all') {
14947 this.doQuery(this.allQuery, true);
14949 this.doQuery(this.getRawValue());
14951 if (!this.blockFocus) {
14952 this.inputEl().focus();
14957 onTickableTriggerClick : function(e)
14964 this.loadNext = false;
14965 this.hasFocus = true;
14967 if(this.triggerAction == 'all') {
14968 this.doQuery(this.allQuery, true);
14970 this.doQuery(this.getRawValue());
14974 onSearchFieldClick : function(e)
14976 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14977 this.onTickableFooterButtonClick(e, false, false);
14981 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14986 this.loadNext = false;
14987 this.hasFocus = true;
14989 if(this.triggerAction == 'all') {
14990 this.doQuery(this.allQuery, true);
14992 this.doQuery(this.getRawValue());
14996 listKeyPress : function(e)
14998 //Roo.log('listkeypress');
14999 // scroll to first matching element based on key pres..
15000 if (e.isSpecialKey()) {
15003 var k = String.fromCharCode(e.getKey()).toUpperCase();
15006 var csel = this.view.getSelectedNodes();
15007 var cselitem = false;
15009 var ix = this.view.indexOf(csel[0]);
15010 cselitem = this.store.getAt(ix);
15011 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15017 this.store.each(function(v) {
15019 // start at existing selection.
15020 if (cselitem.id == v.id) {
15026 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15027 match = this.store.indexOf(v);
15033 if (match === false) {
15034 return true; // no more action?
15037 this.view.select(match);
15038 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15039 sn.scrollIntoView(sn.dom.parentNode, false);
15042 onViewScroll : function(e, t){
15044 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){
15048 this.hasQuery = true;
15050 this.loading = this.list.select('.loading', true).first();
15052 if(this.loading === null){
15053 this.list.createChild({
15055 cls: 'loading roo-select2-more-results roo-select2-active',
15056 html: 'Loading more results...'
15059 this.loading = this.list.select('.loading', true).first();
15061 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15063 this.loading.hide();
15066 this.loading.show();
15071 this.loadNext = true;
15073 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15078 addItem : function(o)
15080 var dv = ''; // display value
15082 if (this.displayField) {
15083 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15085 // this is an error condition!!!
15086 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15093 var choice = this.choices.createChild({
15095 cls: 'roo-select2-search-choice',
15104 cls: 'roo-select2-search-choice-close fa fa-times',
15109 }, this.searchField);
15111 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15113 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15121 this.inputEl().dom.value = '';
15126 onRemoveItem : function(e, _self, o)
15128 e.preventDefault();
15130 this.lastItem = Roo.apply([], this.item);
15132 var index = this.item.indexOf(o.data) * 1;
15135 Roo.log('not this item?!');
15139 this.item.splice(index, 1);
15144 this.fireEvent('remove', this, e);
15150 syncValue : function()
15152 if(!this.item.length){
15159 Roo.each(this.item, function(i){
15160 if(_this.valueField){
15161 value.push(i[_this.valueField]);
15168 this.value = value.join(',');
15170 if(this.hiddenField){
15171 this.hiddenField.dom.value = this.value;
15174 this.store.fireEvent("datachanged", this.store);
15179 clearItem : function()
15181 if(!this.multiple){
15187 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15195 if(this.tickable && !Roo.isTouch){
15196 this.view.refresh();
15200 inputEl: function ()
15202 if(Roo.isIOS && this.useNativeIOS){
15203 return this.el.select('select.roo-ios-select', true).first();
15206 if(Roo.isTouch && this.mobileTouchView){
15207 return this.el.select('input.form-control',true).first();
15211 return this.searchField;
15214 return this.el.select('input.form-control',true).first();
15217 onTickableFooterButtonClick : function(e, btn, el)
15219 e.preventDefault();
15221 this.lastItem = Roo.apply([], this.item);
15223 if(btn && btn.name == 'cancel'){
15224 this.tickItems = Roo.apply([], this.item);
15233 Roo.each(this.tickItems, function(o){
15241 validate : function()
15243 if(this.getVisibilityEl().hasClass('hidden')){
15247 var v = this.getRawValue();
15250 v = this.getValue();
15253 if(this.disabled || this.allowBlank || v.length){
15258 this.markInvalid();
15262 tickableInputEl : function()
15264 if(!this.tickable || !this.editable){
15265 return this.inputEl();
15268 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15272 getAutoCreateTouchView : function()
15277 cls: 'form-group' //input-group
15283 type : this.inputType,
15284 cls : 'form-control x-combo-noedit',
15285 autocomplete: 'new-password',
15286 placeholder : this.placeholder || '',
15291 input.name = this.name;
15295 input.cls += ' input-' + this.size;
15298 if (this.disabled) {
15299 input.disabled = true;
15310 inputblock.cls += ' input-group';
15312 inputblock.cn.unshift({
15314 cls : 'input-group-addon input-group-prepend input-group-text',
15319 if(this.removable && !this.multiple){
15320 inputblock.cls += ' roo-removable';
15322 inputblock.cn.push({
15325 cls : 'roo-combo-removable-btn close'
15329 if(this.hasFeedback && !this.allowBlank){
15331 inputblock.cls += ' has-feedback';
15333 inputblock.cn.push({
15335 cls: 'glyphicon form-control-feedback'
15342 inputblock.cls += (this.before) ? '' : ' input-group';
15344 inputblock.cn.push({
15346 cls : 'input-group-addon input-group-append input-group-text',
15352 var ibwrap = inputblock;
15357 cls: 'roo-select2-choices',
15361 cls: 'roo-select2-search-field',
15374 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15379 cls: 'form-hidden-field'
15385 if(!this.multiple && this.showToggleBtn){
15391 if (this.caret != false) {
15394 cls: 'fa fa-' + this.caret
15401 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15403 Roo.bootstrap.version == 3 ? caret : '',
15406 cls: 'combobox-clear',
15420 combobox.cls += ' roo-select2-container-multi';
15423 var align = this.labelAlign || this.parentLabelAlign();
15425 if (align ==='left' && this.fieldLabel.length) {
15430 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15431 tooltip : 'This field is required'
15435 cls : 'control-label col-form-label',
15436 html : this.fieldLabel
15447 var labelCfg = cfg.cn[1];
15448 var contentCfg = cfg.cn[2];
15451 if(this.indicatorpos == 'right'){
15456 cls : 'control-label col-form-label',
15460 html : this.fieldLabel
15464 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15465 tooltip : 'This field is required'
15478 labelCfg = cfg.cn[0];
15479 contentCfg = cfg.cn[1];
15484 if(this.labelWidth > 12){
15485 labelCfg.style = "width: " + this.labelWidth + 'px';
15488 if(this.labelWidth < 13 && this.labelmd == 0){
15489 this.labelmd = this.labelWidth;
15492 if(this.labellg > 0){
15493 labelCfg.cls += ' col-lg-' + this.labellg;
15494 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15497 if(this.labelmd > 0){
15498 labelCfg.cls += ' col-md-' + this.labelmd;
15499 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15502 if(this.labelsm > 0){
15503 labelCfg.cls += ' col-sm-' + this.labelsm;
15504 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15507 if(this.labelxs > 0){
15508 labelCfg.cls += ' col-xs-' + this.labelxs;
15509 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15513 } else if ( this.fieldLabel.length) {
15517 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15518 tooltip : 'This field is required'
15522 cls : 'control-label',
15523 html : this.fieldLabel
15534 if(this.indicatorpos == 'right'){
15538 cls : 'control-label',
15539 html : this.fieldLabel,
15543 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15544 tooltip : 'This field is required'
15561 var settings = this;
15563 ['xs','sm','md','lg'].map(function(size){
15564 if (settings[size]) {
15565 cfg.cls += ' col-' + size + '-' + settings[size];
15572 initTouchView : function()
15574 this.renderTouchView();
15576 this.touchViewEl.on('scroll', function(){
15577 this.el.dom.scrollTop = 0;
15580 this.originalValue = this.getValue();
15582 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15584 this.inputEl().on("click", this.showTouchView, this);
15585 if (this.triggerEl) {
15586 this.triggerEl.on("click", this.showTouchView, this);
15590 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15591 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15593 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15595 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15596 this.store.on('load', this.onTouchViewLoad, this);
15597 this.store.on('loadexception', this.onTouchViewLoadException, this);
15599 if(this.hiddenName){
15601 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15603 this.hiddenField.dom.value =
15604 this.hiddenValue !== undefined ? this.hiddenValue :
15605 this.value !== undefined ? this.value : '';
15607 this.el.dom.removeAttribute('name');
15608 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15612 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15613 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15616 if(this.removable && !this.multiple){
15617 var close = this.closeTriggerEl();
15619 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15620 close.on('click', this.removeBtnClick, this, close);
15624 * fix the bug in Safari iOS8
15626 this.inputEl().on("focus", function(e){
15627 document.activeElement.blur();
15630 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15637 renderTouchView : function()
15639 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15640 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15642 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15643 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15645 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15646 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15647 this.touchViewBodyEl.setStyle('overflow', 'auto');
15649 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15650 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15652 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15653 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15657 showTouchView : function()
15663 this.touchViewHeaderEl.hide();
15665 if(this.modalTitle.length){
15666 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15667 this.touchViewHeaderEl.show();
15670 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15671 this.touchViewEl.show();
15673 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15675 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15676 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15678 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15680 if(this.modalTitle.length){
15681 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15684 this.touchViewBodyEl.setHeight(bodyHeight);
15688 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15690 this.touchViewEl.addClass('in');
15693 if(this._touchViewMask){
15694 Roo.get(document.body).addClass("x-body-masked");
15695 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15696 this._touchViewMask.setStyle('z-index', 10000);
15697 this._touchViewMask.addClass('show');
15700 this.doTouchViewQuery();
15704 hideTouchView : function()
15706 this.touchViewEl.removeClass('in');
15710 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15712 this.touchViewEl.setStyle('display', 'none');
15715 if(this._touchViewMask){
15716 this._touchViewMask.removeClass('show');
15717 Roo.get(document.body).removeClass("x-body-masked");
15721 setTouchViewValue : function()
15728 Roo.each(this.tickItems, function(o){
15733 this.hideTouchView();
15736 doTouchViewQuery : function()
15745 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15749 if(!this.alwaysQuery || this.mode == 'local'){
15750 this.onTouchViewLoad();
15757 onTouchViewBeforeLoad : function(combo,opts)
15763 onTouchViewLoad : function()
15765 if(this.store.getCount() < 1){
15766 this.onTouchViewEmptyResults();
15770 this.clearTouchView();
15772 var rawValue = this.getRawValue();
15774 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15776 this.tickItems = [];
15778 this.store.data.each(function(d, rowIndex){
15779 var row = this.touchViewListGroup.createChild(template);
15781 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15782 row.addClass(d.data.cls);
15785 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15788 html : d.data[this.displayField]
15791 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15792 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15795 row.removeClass('selected');
15796 if(!this.multiple && this.valueField &&
15797 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15800 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15801 row.addClass('selected');
15804 if(this.multiple && this.valueField &&
15805 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15809 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15810 this.tickItems.push(d.data);
15813 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15817 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15819 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15821 if(this.modalTitle.length){
15822 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15825 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15827 if(this.mobile_restrict_height && listHeight < bodyHeight){
15828 this.touchViewBodyEl.setHeight(listHeight);
15833 if(firstChecked && listHeight > bodyHeight){
15834 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15839 onTouchViewLoadException : function()
15841 this.hideTouchView();
15844 onTouchViewEmptyResults : function()
15846 this.clearTouchView();
15848 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15850 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15854 clearTouchView : function()
15856 this.touchViewListGroup.dom.innerHTML = '';
15859 onTouchViewClick : function(e, el, o)
15861 e.preventDefault();
15864 var rowIndex = o.rowIndex;
15866 var r = this.store.getAt(rowIndex);
15868 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15870 if(!this.multiple){
15871 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15872 c.dom.removeAttribute('checked');
15875 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15877 this.setFromData(r.data);
15879 var close = this.closeTriggerEl();
15885 this.hideTouchView();
15887 this.fireEvent('select', this, r, rowIndex);
15892 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15893 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15894 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15898 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15899 this.addItem(r.data);
15900 this.tickItems.push(r.data);
15904 getAutoCreateNativeIOS : function()
15907 cls: 'form-group' //input-group,
15912 cls : 'roo-ios-select'
15916 combobox.name = this.name;
15919 if (this.disabled) {
15920 combobox.disabled = true;
15923 var settings = this;
15925 ['xs','sm','md','lg'].map(function(size){
15926 if (settings[size]) {
15927 cfg.cls += ' col-' + size + '-' + settings[size];
15937 initIOSView : function()
15939 this.store.on('load', this.onIOSViewLoad, this);
15944 onIOSViewLoad : function()
15946 if(this.store.getCount() < 1){
15950 this.clearIOSView();
15952 if(this.allowBlank) {
15954 var default_text = '-- SELECT --';
15956 if(this.placeholder.length){
15957 default_text = this.placeholder;
15960 if(this.emptyTitle.length){
15961 default_text += ' - ' + this.emptyTitle + ' -';
15964 var opt = this.inputEl().createChild({
15967 html : default_text
15971 o[this.valueField] = 0;
15972 o[this.displayField] = default_text;
15974 this.ios_options.push({
15981 this.store.data.each(function(d, rowIndex){
15985 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15986 html = d.data[this.displayField];
15991 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15992 value = d.data[this.valueField];
16001 if(this.value == d.data[this.valueField]){
16002 option['selected'] = true;
16005 var opt = this.inputEl().createChild(option);
16007 this.ios_options.push({
16014 this.inputEl().on('change', function(){
16015 this.fireEvent('select', this);
16020 clearIOSView: function()
16022 this.inputEl().dom.innerHTML = '';
16024 this.ios_options = [];
16027 setIOSValue: function(v)
16031 if(!this.ios_options){
16035 Roo.each(this.ios_options, function(opts){
16037 opts.el.dom.removeAttribute('selected');
16039 if(opts.data[this.valueField] != v){
16043 opts.el.dom.setAttribute('selected', true);
16049 * @cfg {Boolean} grow
16053 * @cfg {Number} growMin
16057 * @cfg {Number} growMax
16066 Roo.apply(Roo.bootstrap.ComboBox, {
16070 cls: 'modal-header',
16092 cls: 'list-group-item',
16096 cls: 'roo-combobox-list-group-item-value'
16100 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16114 listItemCheckbox : {
16116 cls: 'list-group-item',
16120 cls: 'roo-combobox-list-group-item-value'
16124 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16140 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16145 cls: 'modal-footer',
16153 cls: 'col-xs-6 text-left',
16156 cls: 'btn btn-danger roo-touch-view-cancel',
16162 cls: 'col-xs-6 text-right',
16165 cls: 'btn btn-success roo-touch-view-ok',
16176 Roo.apply(Roo.bootstrap.ComboBox, {
16178 touchViewTemplate : {
16180 cls: 'modal fade roo-combobox-touch-view',
16184 cls: 'modal-dialog',
16185 style : 'position:fixed', // we have to fix position....
16189 cls: 'modal-content',
16191 Roo.bootstrap.ComboBox.header,
16192 Roo.bootstrap.ComboBox.body,
16193 Roo.bootstrap.ComboBox.footer
16202 * Ext JS Library 1.1.1
16203 * Copyright(c) 2006-2007, Ext JS, LLC.
16205 * Originally Released Under LGPL - original licence link has changed is not relivant.
16208 * <script type="text/javascript">
16213 * @extends Roo.util.Observable
16214 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16215 * This class also supports single and multi selection modes. <br>
16216 * Create a data model bound view:
16218 var store = new Roo.data.Store(...);
16220 var view = new Roo.View({
16222 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16224 singleSelect: true,
16225 selectedClass: "ydataview-selected",
16229 // listen for node click?
16230 view.on("click", function(vw, index, node, e){
16231 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16235 dataModel.load("foobar.xml");
16237 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16239 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16240 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16242 * Note: old style constructor is still suported (container, template, config)
16245 * Create a new View
16246 * @param {Object} config The config object
16249 Roo.View = function(config, depreciated_tpl, depreciated_config){
16251 this.parent = false;
16253 if (typeof(depreciated_tpl) == 'undefined') {
16254 // new way.. - universal constructor.
16255 Roo.apply(this, config);
16256 this.el = Roo.get(this.el);
16259 this.el = Roo.get(config);
16260 this.tpl = depreciated_tpl;
16261 Roo.apply(this, depreciated_config);
16263 this.wrapEl = this.el.wrap().wrap();
16264 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16267 if(typeof(this.tpl) == "string"){
16268 this.tpl = new Roo.Template(this.tpl);
16270 // support xtype ctors..
16271 this.tpl = new Roo.factory(this.tpl, Roo);
16275 this.tpl.compile();
16280 * @event beforeclick
16281 * Fires before a click is processed. Returns false to cancel the default action.
16282 * @param {Roo.View} this
16283 * @param {Number} index The index of the target node
16284 * @param {HTMLElement} node The target node
16285 * @param {Roo.EventObject} e The raw event object
16287 "beforeclick" : true,
16290 * Fires when a template node is clicked.
16291 * @param {Roo.View} this
16292 * @param {Number} index The index of the target node
16293 * @param {HTMLElement} node The target node
16294 * @param {Roo.EventObject} e The raw event object
16299 * Fires when a template node is double clicked.
16300 * @param {Roo.View} this
16301 * @param {Number} index The index of the target node
16302 * @param {HTMLElement} node The target node
16303 * @param {Roo.EventObject} e The raw event object
16307 * @event contextmenu
16308 * Fires when a template node is right clicked.
16309 * @param {Roo.View} this
16310 * @param {Number} index The index of the target node
16311 * @param {HTMLElement} node The target node
16312 * @param {Roo.EventObject} e The raw event object
16314 "contextmenu" : true,
16316 * @event selectionchange
16317 * Fires when the selected nodes change.
16318 * @param {Roo.View} this
16319 * @param {Array} selections Array of the selected nodes
16321 "selectionchange" : true,
16324 * @event beforeselect
16325 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16326 * @param {Roo.View} this
16327 * @param {HTMLElement} node The node to be selected
16328 * @param {Array} selections Array of currently selected nodes
16330 "beforeselect" : true,
16332 * @event preparedata
16333 * Fires on every row to render, to allow you to change the data.
16334 * @param {Roo.View} this
16335 * @param {Object} data to be rendered (change this)
16337 "preparedata" : true
16345 "click": this.onClick,
16346 "dblclick": this.onDblClick,
16347 "contextmenu": this.onContextMenu,
16351 this.selections = [];
16353 this.cmp = new Roo.CompositeElementLite([]);
16355 this.store = Roo.factory(this.store, Roo.data);
16356 this.setStore(this.store, true);
16359 if ( this.footer && this.footer.xtype) {
16361 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16363 this.footer.dataSource = this.store;
16364 this.footer.container = fctr;
16365 this.footer = Roo.factory(this.footer, Roo);
16366 fctr.insertFirst(this.el);
16368 // this is a bit insane - as the paging toolbar seems to detach the el..
16369 // dom.parentNode.parentNode.parentNode
16370 // they get detached?
16374 Roo.View.superclass.constructor.call(this);
16379 Roo.extend(Roo.View, Roo.util.Observable, {
16382 * @cfg {Roo.data.Store} store Data store to load data from.
16387 * @cfg {String|Roo.Element} el The container element.
16392 * @cfg {String|Roo.Template} tpl The template used by this View
16396 * @cfg {String} dataName the named area of the template to use as the data area
16397 * Works with domtemplates roo-name="name"
16401 * @cfg {String} selectedClass The css class to add to selected nodes
16403 selectedClass : "x-view-selected",
16405 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16410 * @cfg {String} text to display on mask (default Loading)
16414 * @cfg {Boolean} multiSelect Allow multiple selection
16416 multiSelect : false,
16418 * @cfg {Boolean} singleSelect Allow single selection
16420 singleSelect: false,
16423 * @cfg {Boolean} toggleSelect - selecting
16425 toggleSelect : false,
16428 * @cfg {Boolean} tickable - selecting
16433 * Returns the element this view is bound to.
16434 * @return {Roo.Element}
16436 getEl : function(){
16437 return this.wrapEl;
16443 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16445 refresh : function(){
16446 //Roo.log('refresh');
16449 // if we are using something like 'domtemplate', then
16450 // the what gets used is:
16451 // t.applySubtemplate(NAME, data, wrapping data..)
16452 // the outer template then get' applied with
16453 // the store 'extra data'
16454 // and the body get's added to the
16455 // roo-name="data" node?
16456 // <span class='roo-tpl-{name}'></span> ?????
16460 this.clearSelections();
16461 this.el.update("");
16463 var records = this.store.getRange();
16464 if(records.length < 1) {
16466 // is this valid?? = should it render a template??
16468 this.el.update(this.emptyText);
16472 if (this.dataName) {
16473 this.el.update(t.apply(this.store.meta)); //????
16474 el = this.el.child('.roo-tpl-' + this.dataName);
16477 for(var i = 0, len = records.length; i < len; i++){
16478 var data = this.prepareData(records[i].data, i, records[i]);
16479 this.fireEvent("preparedata", this, data, i, records[i]);
16481 var d = Roo.apply({}, data);
16484 Roo.apply(d, {'roo-id' : Roo.id()});
16488 Roo.each(this.parent.item, function(item){
16489 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16492 Roo.apply(d, {'roo-data-checked' : 'checked'});
16496 html[html.length] = Roo.util.Format.trim(
16498 t.applySubtemplate(this.dataName, d, this.store.meta) :
16505 el.update(html.join(""));
16506 this.nodes = el.dom.childNodes;
16507 this.updateIndexes(0);
16512 * Function to override to reformat the data that is sent to
16513 * the template for each node.
16514 * DEPRICATED - use the preparedata event handler.
16515 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16516 * a JSON object for an UpdateManager bound view).
16518 prepareData : function(data, index, record)
16520 this.fireEvent("preparedata", this, data, index, record);
16524 onUpdate : function(ds, record){
16525 // Roo.log('on update');
16526 this.clearSelections();
16527 var index = this.store.indexOf(record);
16528 var n = this.nodes[index];
16529 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16530 n.parentNode.removeChild(n);
16531 this.updateIndexes(index, index);
16537 onAdd : function(ds, records, index)
16539 //Roo.log(['on Add', ds, records, index] );
16540 this.clearSelections();
16541 if(this.nodes.length == 0){
16545 var n = this.nodes[index];
16546 for(var i = 0, len = records.length; i < len; i++){
16547 var d = this.prepareData(records[i].data, i, records[i]);
16549 this.tpl.insertBefore(n, d);
16552 this.tpl.append(this.el, d);
16555 this.updateIndexes(index);
16558 onRemove : function(ds, record, index){
16559 // Roo.log('onRemove');
16560 this.clearSelections();
16561 var el = this.dataName ?
16562 this.el.child('.roo-tpl-' + this.dataName) :
16565 el.dom.removeChild(this.nodes[index]);
16566 this.updateIndexes(index);
16570 * Refresh an individual node.
16571 * @param {Number} index
16573 refreshNode : function(index){
16574 this.onUpdate(this.store, this.store.getAt(index));
16577 updateIndexes : function(startIndex, endIndex){
16578 var ns = this.nodes;
16579 startIndex = startIndex || 0;
16580 endIndex = endIndex || ns.length - 1;
16581 for(var i = startIndex; i <= endIndex; i++){
16582 ns[i].nodeIndex = i;
16587 * Changes the data store this view uses and refresh the view.
16588 * @param {Store} store
16590 setStore : function(store, initial){
16591 if(!initial && this.store){
16592 this.store.un("datachanged", this.refresh);
16593 this.store.un("add", this.onAdd);
16594 this.store.un("remove", this.onRemove);
16595 this.store.un("update", this.onUpdate);
16596 this.store.un("clear", this.refresh);
16597 this.store.un("beforeload", this.onBeforeLoad);
16598 this.store.un("load", this.onLoad);
16599 this.store.un("loadexception", this.onLoad);
16603 store.on("datachanged", this.refresh, this);
16604 store.on("add", this.onAdd, this);
16605 store.on("remove", this.onRemove, this);
16606 store.on("update", this.onUpdate, this);
16607 store.on("clear", this.refresh, this);
16608 store.on("beforeload", this.onBeforeLoad, this);
16609 store.on("load", this.onLoad, this);
16610 store.on("loadexception", this.onLoad, this);
16618 * onbeforeLoad - masks the loading area.
16621 onBeforeLoad : function(store,opts)
16623 //Roo.log('onBeforeLoad');
16625 this.el.update("");
16627 this.el.mask(this.mask ? this.mask : "Loading" );
16629 onLoad : function ()
16636 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16637 * @param {HTMLElement} node
16638 * @return {HTMLElement} The template node
16640 findItemFromChild : function(node){
16641 var el = this.dataName ?
16642 this.el.child('.roo-tpl-' + this.dataName,true) :
16645 if(!node || node.parentNode == el){
16648 var p = node.parentNode;
16649 while(p && p != el){
16650 if(p.parentNode == el){
16659 onClick : function(e){
16660 var item = this.findItemFromChild(e.getTarget());
16662 var index = this.indexOf(item);
16663 if(this.onItemClick(item, index, e) !== false){
16664 this.fireEvent("click", this, index, item, e);
16667 this.clearSelections();
16672 onContextMenu : function(e){
16673 var item = this.findItemFromChild(e.getTarget());
16675 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16680 onDblClick : function(e){
16681 var item = this.findItemFromChild(e.getTarget());
16683 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16687 onItemClick : function(item, index, e)
16689 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16692 if (this.toggleSelect) {
16693 var m = this.isSelected(item) ? 'unselect' : 'select';
16696 _t[m](item, true, false);
16699 if(this.multiSelect || this.singleSelect){
16700 if(this.multiSelect && e.shiftKey && this.lastSelection){
16701 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16703 this.select(item, this.multiSelect && e.ctrlKey);
16704 this.lastSelection = item;
16707 if(!this.tickable){
16708 e.preventDefault();
16716 * Get the number of selected nodes.
16719 getSelectionCount : function(){
16720 return this.selections.length;
16724 * Get the currently selected nodes.
16725 * @return {Array} An array of HTMLElements
16727 getSelectedNodes : function(){
16728 return this.selections;
16732 * Get the indexes of the selected nodes.
16735 getSelectedIndexes : function(){
16736 var indexes = [], s = this.selections;
16737 for(var i = 0, len = s.length; i < len; i++){
16738 indexes.push(s[i].nodeIndex);
16744 * Clear all selections
16745 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16747 clearSelections : function(suppressEvent){
16748 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16749 this.cmp.elements = this.selections;
16750 this.cmp.removeClass(this.selectedClass);
16751 this.selections = [];
16752 if(!suppressEvent){
16753 this.fireEvent("selectionchange", this, this.selections);
16759 * Returns true if the passed node is selected
16760 * @param {HTMLElement/Number} node The node or node index
16761 * @return {Boolean}
16763 isSelected : function(node){
16764 var s = this.selections;
16768 node = this.getNode(node);
16769 return s.indexOf(node) !== -1;
16774 * @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
16775 * @param {Boolean} keepExisting (optional) true to keep existing selections
16776 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16778 select : function(nodeInfo, keepExisting, suppressEvent){
16779 if(nodeInfo instanceof Array){
16781 this.clearSelections(true);
16783 for(var i = 0, len = nodeInfo.length; i < len; i++){
16784 this.select(nodeInfo[i], true, true);
16788 var node = this.getNode(nodeInfo);
16789 if(!node || this.isSelected(node)){
16790 return; // already selected.
16793 this.clearSelections(true);
16796 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16797 Roo.fly(node).addClass(this.selectedClass);
16798 this.selections.push(node);
16799 if(!suppressEvent){
16800 this.fireEvent("selectionchange", this, this.selections);
16808 * @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
16809 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16810 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16812 unselect : function(nodeInfo, keepExisting, suppressEvent)
16814 if(nodeInfo instanceof Array){
16815 Roo.each(this.selections, function(s) {
16816 this.unselect(s, nodeInfo);
16820 var node = this.getNode(nodeInfo);
16821 if(!node || !this.isSelected(node)){
16822 //Roo.log("not selected");
16823 return; // not selected.
16827 Roo.each(this.selections, function(s) {
16829 Roo.fly(node).removeClass(this.selectedClass);
16836 this.selections= ns;
16837 this.fireEvent("selectionchange", this, this.selections);
16841 * Gets a template node.
16842 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16843 * @return {HTMLElement} The node or null if it wasn't found
16845 getNode : function(nodeInfo){
16846 if(typeof nodeInfo == "string"){
16847 return document.getElementById(nodeInfo);
16848 }else if(typeof nodeInfo == "number"){
16849 return this.nodes[nodeInfo];
16855 * Gets a range template nodes.
16856 * @param {Number} startIndex
16857 * @param {Number} endIndex
16858 * @return {Array} An array of nodes
16860 getNodes : function(start, end){
16861 var ns = this.nodes;
16862 start = start || 0;
16863 end = typeof end == "undefined" ? ns.length - 1 : end;
16866 for(var i = start; i <= end; i++){
16870 for(var i = start; i >= end; i--){
16878 * Finds the index of the passed node
16879 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16880 * @return {Number} The index of the node or -1
16882 indexOf : function(node){
16883 node = this.getNode(node);
16884 if(typeof node.nodeIndex == "number"){
16885 return node.nodeIndex;
16887 var ns = this.nodes;
16888 for(var i = 0, len = ns.length; i < len; i++){
16899 * based on jquery fullcalendar
16903 Roo.bootstrap = Roo.bootstrap || {};
16905 * @class Roo.bootstrap.Calendar
16906 * @extends Roo.bootstrap.Component
16907 * Bootstrap Calendar class
16908 * @cfg {Boolean} loadMask (true|false) default false
16909 * @cfg {Object} header generate the user specific header of the calendar, default false
16912 * Create a new Container
16913 * @param {Object} config The config object
16918 Roo.bootstrap.Calendar = function(config){
16919 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16923 * Fires when a date is selected
16924 * @param {DatePicker} this
16925 * @param {Date} date The selected date
16929 * @event monthchange
16930 * Fires when the displayed month changes
16931 * @param {DatePicker} this
16932 * @param {Date} date The selected month
16934 'monthchange': true,
16936 * @event evententer
16937 * Fires when mouse over an event
16938 * @param {Calendar} this
16939 * @param {event} Event
16941 'evententer': true,
16943 * @event eventleave
16944 * Fires when the mouse leaves an
16945 * @param {Calendar} this
16948 'eventleave': true,
16950 * @event eventclick
16951 * Fires when the mouse click an
16952 * @param {Calendar} this
16961 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16964 * @cfg {Number} startDay
16965 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16973 getAutoCreate : function(){
16976 var fc_button = function(name, corner, style, content ) {
16977 return Roo.apply({},{
16979 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16981 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16984 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16995 style : 'width:100%',
17002 cls : 'fc-header-left',
17004 fc_button('prev', 'left', 'arrow', '‹' ),
17005 fc_button('next', 'right', 'arrow', '›' ),
17006 { tag: 'span', cls: 'fc-header-space' },
17007 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17015 cls : 'fc-header-center',
17019 cls: 'fc-header-title',
17022 html : 'month / year'
17030 cls : 'fc-header-right',
17032 /* fc_button('month', 'left', '', 'month' ),
17033 fc_button('week', '', '', 'week' ),
17034 fc_button('day', 'right', '', 'day' )
17046 header = this.header;
17049 var cal_heads = function() {
17051 // fixme - handle this.
17053 for (var i =0; i < Date.dayNames.length; i++) {
17054 var d = Date.dayNames[i];
17057 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17058 html : d.substring(0,3)
17062 ret[0].cls += ' fc-first';
17063 ret[6].cls += ' fc-last';
17066 var cal_cell = function(n) {
17069 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17074 cls: 'fc-day-number',
17078 cls: 'fc-day-content',
17082 style: 'position: relative;' // height: 17px;
17094 var cal_rows = function() {
17097 for (var r = 0; r < 6; r++) {
17104 for (var i =0; i < Date.dayNames.length; i++) {
17105 var d = Date.dayNames[i];
17106 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17109 row.cn[0].cls+=' fc-first';
17110 row.cn[0].cn[0].style = 'min-height:90px';
17111 row.cn[6].cls+=' fc-last';
17115 ret[0].cls += ' fc-first';
17116 ret[4].cls += ' fc-prev-last';
17117 ret[5].cls += ' fc-last';
17124 cls: 'fc-border-separate',
17125 style : 'width:100%',
17133 cls : 'fc-first fc-last',
17151 cls : 'fc-content',
17152 style : "position: relative;",
17155 cls : 'fc-view fc-view-month fc-grid',
17156 style : 'position: relative',
17157 unselectable : 'on',
17160 cls : 'fc-event-container',
17161 style : 'position:absolute;z-index:8;top:0;left:0;'
17179 initEvents : function()
17182 throw "can not find store for calendar";
17188 style: "text-align:center",
17192 style: "background-color:white;width:50%;margin:250 auto",
17196 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17207 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17209 var size = this.el.select('.fc-content', true).first().getSize();
17210 this.maskEl.setSize(size.width, size.height);
17211 this.maskEl.enableDisplayMode("block");
17212 if(!this.loadMask){
17213 this.maskEl.hide();
17216 this.store = Roo.factory(this.store, Roo.data);
17217 this.store.on('load', this.onLoad, this);
17218 this.store.on('beforeload', this.onBeforeLoad, this);
17222 this.cells = this.el.select('.fc-day',true);
17223 //Roo.log(this.cells);
17224 this.textNodes = this.el.query('.fc-day-number');
17225 this.cells.addClassOnOver('fc-state-hover');
17227 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17228 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17229 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17230 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17232 this.on('monthchange', this.onMonthChange, this);
17234 this.update(new Date().clearTime());
17237 resize : function() {
17238 var sz = this.el.getSize();
17240 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17241 this.el.select('.fc-day-content div',true).setHeight(34);
17246 showPrevMonth : function(e){
17247 this.update(this.activeDate.add("mo", -1));
17249 showToday : function(e){
17250 this.update(new Date().clearTime());
17253 showNextMonth : function(e){
17254 this.update(this.activeDate.add("mo", 1));
17258 showPrevYear : function(){
17259 this.update(this.activeDate.add("y", -1));
17263 showNextYear : function(){
17264 this.update(this.activeDate.add("y", 1));
17269 update : function(date)
17271 var vd = this.activeDate;
17272 this.activeDate = date;
17273 // if(vd && this.el){
17274 // var t = date.getTime();
17275 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17276 // Roo.log('using add remove');
17278 // this.fireEvent('monthchange', this, date);
17280 // this.cells.removeClass("fc-state-highlight");
17281 // this.cells.each(function(c){
17282 // if(c.dateValue == t){
17283 // c.addClass("fc-state-highlight");
17284 // setTimeout(function(){
17285 // try{c.dom.firstChild.focus();}catch(e){}
17295 var days = date.getDaysInMonth();
17297 var firstOfMonth = date.getFirstDateOfMonth();
17298 var startingPos = firstOfMonth.getDay()-this.startDay;
17300 if(startingPos < this.startDay){
17304 var pm = date.add(Date.MONTH, -1);
17305 var prevStart = pm.getDaysInMonth()-startingPos;
17307 this.cells = this.el.select('.fc-day',true);
17308 this.textNodes = this.el.query('.fc-day-number');
17309 this.cells.addClassOnOver('fc-state-hover');
17311 var cells = this.cells.elements;
17312 var textEls = this.textNodes;
17314 Roo.each(cells, function(cell){
17315 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17318 days += startingPos;
17320 // convert everything to numbers so it's fast
17321 var day = 86400000;
17322 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17325 //Roo.log(prevStart);
17327 var today = new Date().clearTime().getTime();
17328 var sel = date.clearTime().getTime();
17329 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17330 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17331 var ddMatch = this.disabledDatesRE;
17332 var ddText = this.disabledDatesText;
17333 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17334 var ddaysText = this.disabledDaysText;
17335 var format = this.format;
17337 var setCellClass = function(cal, cell){
17341 //Roo.log('set Cell Class');
17343 var t = d.getTime();
17347 cell.dateValue = t;
17349 cell.className += " fc-today";
17350 cell.className += " fc-state-highlight";
17351 cell.title = cal.todayText;
17354 // disable highlight in other month..
17355 //cell.className += " fc-state-highlight";
17360 cell.className = " fc-state-disabled";
17361 cell.title = cal.minText;
17365 cell.className = " fc-state-disabled";
17366 cell.title = cal.maxText;
17370 if(ddays.indexOf(d.getDay()) != -1){
17371 cell.title = ddaysText;
17372 cell.className = " fc-state-disabled";
17375 if(ddMatch && format){
17376 var fvalue = d.dateFormat(format);
17377 if(ddMatch.test(fvalue)){
17378 cell.title = ddText.replace("%0", fvalue);
17379 cell.className = " fc-state-disabled";
17383 if (!cell.initialClassName) {
17384 cell.initialClassName = cell.dom.className;
17387 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17392 for(; i < startingPos; i++) {
17393 textEls[i].innerHTML = (++prevStart);
17394 d.setDate(d.getDate()+1);
17396 cells[i].className = "fc-past fc-other-month";
17397 setCellClass(this, cells[i]);
17402 for(; i < days; i++){
17403 intDay = i - startingPos + 1;
17404 textEls[i].innerHTML = (intDay);
17405 d.setDate(d.getDate()+1);
17407 cells[i].className = ''; // "x-date-active";
17408 setCellClass(this, cells[i]);
17412 for(; i < 42; i++) {
17413 textEls[i].innerHTML = (++extraDays);
17414 d.setDate(d.getDate()+1);
17416 cells[i].className = "fc-future fc-other-month";
17417 setCellClass(this, cells[i]);
17420 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17422 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17424 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17425 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17427 if(totalRows != 6){
17428 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17429 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17432 this.fireEvent('monthchange', this, date);
17436 if(!this.internalRender){
17437 var main = this.el.dom.firstChild;
17438 var w = main.offsetWidth;
17439 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17440 Roo.fly(main).setWidth(w);
17441 this.internalRender = true;
17442 // opera does not respect the auto grow header center column
17443 // then, after it gets a width opera refuses to recalculate
17444 // without a second pass
17445 if(Roo.isOpera && !this.secondPass){
17446 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17447 this.secondPass = true;
17448 this.update.defer(10, this, [date]);
17455 findCell : function(dt) {
17456 dt = dt.clearTime().getTime();
17458 this.cells.each(function(c){
17459 //Roo.log("check " +c.dateValue + '?=' + dt);
17460 if(c.dateValue == dt){
17470 findCells : function(ev) {
17471 var s = ev.start.clone().clearTime().getTime();
17473 var e= ev.end.clone().clearTime().getTime();
17476 this.cells.each(function(c){
17477 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17479 if(c.dateValue > e){
17482 if(c.dateValue < s){
17491 // findBestRow: function(cells)
17495 // for (var i =0 ; i < cells.length;i++) {
17496 // ret = Math.max(cells[i].rows || 0,ret);
17503 addItem : function(ev)
17505 // look for vertical location slot in
17506 var cells = this.findCells(ev);
17508 // ev.row = this.findBestRow(cells);
17510 // work out the location.
17514 for(var i =0; i < cells.length; i++) {
17516 cells[i].row = cells[0].row;
17519 cells[i].row = cells[i].row + 1;
17529 if (crow.start.getY() == cells[i].getY()) {
17531 crow.end = cells[i];
17548 cells[0].events.push(ev);
17550 this.calevents.push(ev);
17553 clearEvents: function() {
17555 if(!this.calevents){
17559 Roo.each(this.cells.elements, function(c){
17565 Roo.each(this.calevents, function(e) {
17566 Roo.each(e.els, function(el) {
17567 el.un('mouseenter' ,this.onEventEnter, this);
17568 el.un('mouseleave' ,this.onEventLeave, this);
17573 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17579 renderEvents: function()
17583 this.cells.each(function(c) {
17592 if(c.row != c.events.length){
17593 r = 4 - (4 - (c.row - c.events.length));
17596 c.events = ev.slice(0, r);
17597 c.more = ev.slice(r);
17599 if(c.more.length && c.more.length == 1){
17600 c.events.push(c.more.pop());
17603 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17607 this.cells.each(function(c) {
17609 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17612 for (var e = 0; e < c.events.length; e++){
17613 var ev = c.events[e];
17614 var rows = ev.rows;
17616 for(var i = 0; i < rows.length; i++) {
17618 // how many rows should it span..
17621 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17622 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17624 unselectable : "on",
17627 cls: 'fc-event-inner',
17631 // cls: 'fc-event-time',
17632 // html : cells.length > 1 ? '' : ev.time
17636 cls: 'fc-event-title',
17637 html : String.format('{0}', ev.title)
17644 cls: 'ui-resizable-handle ui-resizable-e',
17645 html : '  '
17652 cfg.cls += ' fc-event-start';
17654 if ((i+1) == rows.length) {
17655 cfg.cls += ' fc-event-end';
17658 var ctr = _this.el.select('.fc-event-container',true).first();
17659 var cg = ctr.createChild(cfg);
17661 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17662 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17664 var r = (c.more.length) ? 1 : 0;
17665 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17666 cg.setWidth(ebox.right - sbox.x -2);
17668 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17669 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17670 cg.on('click', _this.onEventClick, _this, ev);
17681 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17682 style : 'position: absolute',
17683 unselectable : "on",
17686 cls: 'fc-event-inner',
17690 cls: 'fc-event-title',
17698 cls: 'ui-resizable-handle ui-resizable-e',
17699 html : '  '
17705 var ctr = _this.el.select('.fc-event-container',true).first();
17706 var cg = ctr.createChild(cfg);
17708 var sbox = c.select('.fc-day-content',true).first().getBox();
17709 var ebox = c.select('.fc-day-content',true).first().getBox();
17711 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17712 cg.setWidth(ebox.right - sbox.x -2);
17714 cg.on('click', _this.onMoreEventClick, _this, c.more);
17724 onEventEnter: function (e, el,event,d) {
17725 this.fireEvent('evententer', this, el, event);
17728 onEventLeave: function (e, el,event,d) {
17729 this.fireEvent('eventleave', this, el, event);
17732 onEventClick: function (e, el,event,d) {
17733 this.fireEvent('eventclick', this, el, event);
17736 onMonthChange: function () {
17740 onMoreEventClick: function(e, el, more)
17744 this.calpopover.placement = 'right';
17745 this.calpopover.setTitle('More');
17747 this.calpopover.setContent('');
17749 var ctr = this.calpopover.el.select('.popover-content', true).first();
17751 Roo.each(more, function(m){
17753 cls : 'fc-event-hori fc-event-draggable',
17756 var cg = ctr.createChild(cfg);
17758 cg.on('click', _this.onEventClick, _this, m);
17761 this.calpopover.show(el);
17766 onLoad: function ()
17768 this.calevents = [];
17771 if(this.store.getCount() > 0){
17772 this.store.data.each(function(d){
17775 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17776 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17777 time : d.data.start_time,
17778 title : d.data.title,
17779 description : d.data.description,
17780 venue : d.data.venue
17785 this.renderEvents();
17787 if(this.calevents.length && this.loadMask){
17788 this.maskEl.hide();
17792 onBeforeLoad: function()
17794 this.clearEvents();
17796 this.maskEl.show();
17810 * @class Roo.bootstrap.Popover
17811 * @extends Roo.bootstrap.Component
17812 * Bootstrap Popover class
17813 * @cfg {String} html contents of the popover (or false to use children..)
17814 * @cfg {String} title of popover (or false to hide)
17815 * @cfg {String} placement how it is placed
17816 * @cfg {String} trigger click || hover (or false to trigger manually)
17817 * @cfg {String} over what (parent or false to trigger manually.)
17818 * @cfg {Number} delay - delay before showing
17821 * Create a new Popover
17822 * @param {Object} config The config object
17825 Roo.bootstrap.Popover = function(config){
17826 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17832 * After the popover show
17834 * @param {Roo.bootstrap.Popover} this
17839 * After the popover hide
17841 * @param {Roo.bootstrap.Popover} this
17847 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17849 title: 'Fill in a title',
17852 placement : 'right',
17853 trigger : 'hover', // hover
17859 can_build_overlaid : false,
17861 getChildContainer : function()
17863 return this.el.select('.popover-content',true).first();
17866 getAutoCreate : function(){
17869 cls : 'popover roo-dynamic',
17870 style: 'display:block',
17876 cls : 'popover-inner',
17880 cls: 'popover-title popover-header',
17884 cls : 'popover-content popover-body',
17895 setTitle: function(str)
17898 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17900 setContent: function(str)
17903 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17905 // as it get's added to the bottom of the page.
17906 onRender : function(ct, position)
17908 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17910 var cfg = Roo.apply({}, this.getAutoCreate());
17914 cfg.cls += ' ' + this.cls;
17917 cfg.style = this.style;
17919 //Roo.log("adding to ");
17920 this.el = Roo.get(document.body).createChild(cfg, position);
17921 // Roo.log(this.el);
17926 initEvents : function()
17928 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17929 this.el.enableDisplayMode('block');
17931 if (this.over === false) {
17934 if (this.triggers === false) {
17937 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17938 var triggers = this.trigger ? this.trigger.split(' ') : [];
17939 Roo.each(triggers, function(trigger) {
17941 if (trigger == 'click') {
17942 on_el.on('click', this.toggle, this);
17943 } else if (trigger != 'manual') {
17944 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17945 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17947 on_el.on(eventIn ,this.enter, this);
17948 on_el.on(eventOut, this.leave, this);
17959 toggle : function () {
17960 this.hoverState == 'in' ? this.leave() : this.enter();
17963 enter : function () {
17965 clearTimeout(this.timeout);
17967 this.hoverState = 'in';
17969 if (!this.delay || !this.delay.show) {
17974 this.timeout = setTimeout(function () {
17975 if (_t.hoverState == 'in') {
17978 }, this.delay.show)
17981 leave : function() {
17982 clearTimeout(this.timeout);
17984 this.hoverState = 'out';
17986 if (!this.delay || !this.delay.hide) {
17991 this.timeout = setTimeout(function () {
17992 if (_t.hoverState == 'out') {
17995 }, this.delay.hide)
17998 show : function (on_el)
18001 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18005 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18006 if (this.html !== false) {
18007 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18009 this.el.removeClass([
18010 'fade','top','bottom', 'left', 'right','in',
18011 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18013 if (!this.title.length) {
18014 this.el.select('.popover-title',true).hide();
18017 var placement = typeof this.placement == 'function' ?
18018 this.placement.call(this, this.el, on_el) :
18021 var autoToken = /\s?auto?\s?/i;
18022 var autoPlace = autoToken.test(placement);
18024 placement = placement.replace(autoToken, '') || 'top';
18028 //this.el.setXY([0,0]);
18030 this.el.dom.style.display='block';
18031 this.el.addClass(placement);
18033 //this.el.appendTo(on_el);
18035 var p = this.getPosition();
18036 var box = this.el.getBox();
18041 var align = Roo.bootstrap.Popover.alignment[placement];
18044 this.el.alignTo(on_el, align[0],align[1]);
18045 //var arrow = this.el.select('.arrow',true).first();
18046 //arrow.set(align[2],
18048 this.el.addClass('in');
18051 if (this.el.hasClass('fade')) {
18055 this.hoverState = 'in';
18057 this.fireEvent('show', this);
18062 this.el.setXY([0,0]);
18063 this.el.removeClass('in');
18065 this.hoverState = null;
18067 this.fireEvent('hide', this);
18072 Roo.bootstrap.Popover.alignment = {
18073 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18074 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18075 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18076 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18087 * @class Roo.bootstrap.Progress
18088 * @extends Roo.bootstrap.Component
18089 * Bootstrap Progress class
18090 * @cfg {Boolean} striped striped of the progress bar
18091 * @cfg {Boolean} active animated of the progress bar
18095 * Create a new Progress
18096 * @param {Object} config The config object
18099 Roo.bootstrap.Progress = function(config){
18100 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18103 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18108 getAutoCreate : function(){
18116 cfg.cls += ' progress-striped';
18120 cfg.cls += ' active';
18139 * @class Roo.bootstrap.ProgressBar
18140 * @extends Roo.bootstrap.Component
18141 * Bootstrap ProgressBar class
18142 * @cfg {Number} aria_valuenow aria-value now
18143 * @cfg {Number} aria_valuemin aria-value min
18144 * @cfg {Number} aria_valuemax aria-value max
18145 * @cfg {String} label label for the progress bar
18146 * @cfg {String} panel (success | info | warning | danger )
18147 * @cfg {String} role role of the progress bar
18148 * @cfg {String} sr_only text
18152 * Create a new ProgressBar
18153 * @param {Object} config The config object
18156 Roo.bootstrap.ProgressBar = function(config){
18157 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18160 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18164 aria_valuemax : 100,
18170 getAutoCreate : function()
18175 cls: 'progress-bar',
18176 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18188 cfg.role = this.role;
18191 if(this.aria_valuenow){
18192 cfg['aria-valuenow'] = this.aria_valuenow;
18195 if(this.aria_valuemin){
18196 cfg['aria-valuemin'] = this.aria_valuemin;
18199 if(this.aria_valuemax){
18200 cfg['aria-valuemax'] = this.aria_valuemax;
18203 if(this.label && !this.sr_only){
18204 cfg.html = this.label;
18208 cfg.cls += ' progress-bar-' + this.panel;
18214 update : function(aria_valuenow)
18216 this.aria_valuenow = aria_valuenow;
18218 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18233 * @class Roo.bootstrap.TabGroup
18234 * @extends Roo.bootstrap.Column
18235 * Bootstrap Column class
18236 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18237 * @cfg {Boolean} carousel true to make the group behave like a carousel
18238 * @cfg {Boolean} bullets show bullets for the panels
18239 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18240 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18241 * @cfg {Boolean} showarrow (true|false) show arrow default true
18244 * Create a new TabGroup
18245 * @param {Object} config The config object
18248 Roo.bootstrap.TabGroup = function(config){
18249 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18251 this.navId = Roo.id();
18254 Roo.bootstrap.TabGroup.register(this);
18258 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18261 transition : false,
18266 slideOnTouch : false,
18269 getAutoCreate : function()
18271 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18273 cfg.cls += ' tab-content';
18275 if (this.carousel) {
18276 cfg.cls += ' carousel slide';
18279 cls : 'carousel-inner',
18283 if(this.bullets && !Roo.isTouch){
18286 cls : 'carousel-bullets',
18290 if(this.bullets_cls){
18291 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18298 cfg.cn[0].cn.push(bullets);
18301 if(this.showarrow){
18302 cfg.cn[0].cn.push({
18304 class : 'carousel-arrow',
18308 class : 'carousel-prev',
18312 class : 'fa fa-chevron-left'
18318 class : 'carousel-next',
18322 class : 'fa fa-chevron-right'
18335 initEvents: function()
18337 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18338 // this.el.on("touchstart", this.onTouchStart, this);
18341 if(this.autoslide){
18344 this.slideFn = window.setInterval(function() {
18345 _this.showPanelNext();
18349 if(this.showarrow){
18350 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18351 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18357 // onTouchStart : function(e, el, o)
18359 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18363 // this.showPanelNext();
18367 getChildContainer : function()
18369 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18373 * register a Navigation item
18374 * @param {Roo.bootstrap.NavItem} the navitem to add
18376 register : function(item)
18378 this.tabs.push( item);
18379 item.navId = this.navId; // not really needed..
18384 getActivePanel : function()
18387 Roo.each(this.tabs, function(t) {
18397 getPanelByName : function(n)
18400 Roo.each(this.tabs, function(t) {
18401 if (t.tabId == n) {
18409 indexOfPanel : function(p)
18412 Roo.each(this.tabs, function(t,i) {
18413 if (t.tabId == p.tabId) {
18422 * show a specific panel
18423 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18424 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18426 showPanel : function (pan)
18428 if(this.transition || typeof(pan) == 'undefined'){
18429 Roo.log("waiting for the transitionend");
18433 if (typeof(pan) == 'number') {
18434 pan = this.tabs[pan];
18437 if (typeof(pan) == 'string') {
18438 pan = this.getPanelByName(pan);
18441 var cur = this.getActivePanel();
18444 Roo.log('pan or acitve pan is undefined');
18448 if (pan.tabId == this.getActivePanel().tabId) {
18452 if (false === cur.fireEvent('beforedeactivate')) {
18456 if(this.bullets > 0 && !Roo.isTouch){
18457 this.setActiveBullet(this.indexOfPanel(pan));
18460 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18462 //class="carousel-item carousel-item-next carousel-item-left"
18464 this.transition = true;
18465 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18466 var lr = dir == 'next' ? 'left' : 'right';
18467 pan.el.addClass(dir); // or prev
18468 pan.el.addClass('carousel-item-' + dir); // or prev
18469 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18470 cur.el.addClass(lr); // or right
18471 pan.el.addClass(lr);
18472 cur.el.addClass('carousel-item-' +lr); // or right
18473 pan.el.addClass('carousel-item-' +lr);
18477 cur.el.on('transitionend', function() {
18478 Roo.log("trans end?");
18480 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18481 pan.setActive(true);
18483 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18484 cur.setActive(false);
18486 _this.transition = false;
18488 }, this, { single: true } );
18493 cur.setActive(false);
18494 pan.setActive(true);
18499 showPanelNext : function()
18501 var i = this.indexOfPanel(this.getActivePanel());
18503 if (i >= this.tabs.length - 1 && !this.autoslide) {
18507 if (i >= this.tabs.length - 1 && this.autoslide) {
18511 this.showPanel(this.tabs[i+1]);
18514 showPanelPrev : function()
18516 var i = this.indexOfPanel(this.getActivePanel());
18518 if (i < 1 && !this.autoslide) {
18522 if (i < 1 && this.autoslide) {
18523 i = this.tabs.length;
18526 this.showPanel(this.tabs[i-1]);
18530 addBullet: function()
18532 if(!this.bullets || Roo.isTouch){
18535 var ctr = this.el.select('.carousel-bullets',true).first();
18536 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18537 var bullet = ctr.createChild({
18538 cls : 'bullet bullet-' + i
18539 },ctr.dom.lastChild);
18544 bullet.on('click', (function(e, el, o, ii, t){
18546 e.preventDefault();
18548 this.showPanel(ii);
18550 if(this.autoslide && this.slideFn){
18551 clearInterval(this.slideFn);
18552 this.slideFn = window.setInterval(function() {
18553 _this.showPanelNext();
18557 }).createDelegate(this, [i, bullet], true));
18562 setActiveBullet : function(i)
18568 Roo.each(this.el.select('.bullet', true).elements, function(el){
18569 el.removeClass('selected');
18572 var bullet = this.el.select('.bullet-' + i, true).first();
18578 bullet.addClass('selected');
18589 Roo.apply(Roo.bootstrap.TabGroup, {
18593 * register a Navigation Group
18594 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18596 register : function(navgrp)
18598 this.groups[navgrp.navId] = navgrp;
18602 * fetch a Navigation Group based on the navigation ID
18603 * if one does not exist , it will get created.
18604 * @param {string} the navgroup to add
18605 * @returns {Roo.bootstrap.NavGroup} the navgroup
18607 get: function(navId) {
18608 if (typeof(this.groups[navId]) == 'undefined') {
18609 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18611 return this.groups[navId] ;
18626 * @class Roo.bootstrap.TabPanel
18627 * @extends Roo.bootstrap.Component
18628 * Bootstrap TabPanel class
18629 * @cfg {Boolean} active panel active
18630 * @cfg {String} html panel content
18631 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18632 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18633 * @cfg {String} href click to link..
18637 * Create a new TabPanel
18638 * @param {Object} config The config object
18641 Roo.bootstrap.TabPanel = function(config){
18642 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18646 * Fires when the active status changes
18647 * @param {Roo.bootstrap.TabPanel} this
18648 * @param {Boolean} state the new state
18653 * @event beforedeactivate
18654 * Fires before a tab is de-activated - can be used to do validation on a form.
18655 * @param {Roo.bootstrap.TabPanel} this
18656 * @return {Boolean} false if there is an error
18659 'beforedeactivate': true
18662 this.tabId = this.tabId || Roo.id();
18666 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18674 getAutoCreate : function(){
18679 // item is needed for carousel - not sure if it has any effect otherwise
18680 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18681 html: this.html || ''
18685 cfg.cls += ' active';
18689 cfg.tabId = this.tabId;
18697 initEvents: function()
18699 var p = this.parent();
18701 this.navId = this.navId || p.navId;
18703 if (typeof(this.navId) != 'undefined') {
18704 // not really needed.. but just in case.. parent should be a NavGroup.
18705 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18709 var i = tg.tabs.length - 1;
18711 if(this.active && tg.bullets > 0 && i < tg.bullets){
18712 tg.setActiveBullet(i);
18716 this.el.on('click', this.onClick, this);
18719 this.el.on("touchstart", this.onTouchStart, this);
18720 this.el.on("touchmove", this.onTouchMove, this);
18721 this.el.on("touchend", this.onTouchEnd, this);
18726 onRender : function(ct, position)
18728 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18731 setActive : function(state)
18733 Roo.log("panel - set active " + this.tabId + "=" + state);
18735 this.active = state;
18737 this.el.removeClass('active');
18739 } else if (!this.el.hasClass('active')) {
18740 this.el.addClass('active');
18743 this.fireEvent('changed', this, state);
18746 onClick : function(e)
18748 e.preventDefault();
18750 if(!this.href.length){
18754 window.location.href = this.href;
18763 onTouchStart : function(e)
18765 this.swiping = false;
18767 this.startX = e.browserEvent.touches[0].clientX;
18768 this.startY = e.browserEvent.touches[0].clientY;
18771 onTouchMove : function(e)
18773 this.swiping = true;
18775 this.endX = e.browserEvent.touches[0].clientX;
18776 this.endY = e.browserEvent.touches[0].clientY;
18779 onTouchEnd : function(e)
18786 var tabGroup = this.parent();
18788 if(this.endX > this.startX){ // swiping right
18789 tabGroup.showPanelPrev();
18793 if(this.startX > this.endX){ // swiping left
18794 tabGroup.showPanelNext();
18813 * @class Roo.bootstrap.DateField
18814 * @extends Roo.bootstrap.Input
18815 * Bootstrap DateField class
18816 * @cfg {Number} weekStart default 0
18817 * @cfg {String} viewMode default empty, (months|years)
18818 * @cfg {String} minViewMode default empty, (months|years)
18819 * @cfg {Number} startDate default -Infinity
18820 * @cfg {Number} endDate default Infinity
18821 * @cfg {Boolean} todayHighlight default false
18822 * @cfg {Boolean} todayBtn default false
18823 * @cfg {Boolean} calendarWeeks default false
18824 * @cfg {Object} daysOfWeekDisabled default empty
18825 * @cfg {Boolean} singleMode default false (true | false)
18827 * @cfg {Boolean} keyboardNavigation default true
18828 * @cfg {String} language default en
18831 * Create a new DateField
18832 * @param {Object} config The config object
18835 Roo.bootstrap.DateField = function(config){
18836 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18840 * Fires when this field show.
18841 * @param {Roo.bootstrap.DateField} this
18842 * @param {Mixed} date The date value
18847 * Fires when this field hide.
18848 * @param {Roo.bootstrap.DateField} this
18849 * @param {Mixed} date The date value
18854 * Fires when select a date.
18855 * @param {Roo.bootstrap.DateField} this
18856 * @param {Mixed} date The date value
18860 * @event beforeselect
18861 * Fires when before select a date.
18862 * @param {Roo.bootstrap.DateField} this
18863 * @param {Mixed} date The date value
18865 beforeselect : true
18869 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18872 * @cfg {String} format
18873 * The default date format string which can be overriden for localization support. The format must be
18874 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18878 * @cfg {String} altFormats
18879 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18880 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18882 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18890 todayHighlight : false,
18896 keyboardNavigation: true,
18898 calendarWeeks: false,
18900 startDate: -Infinity,
18904 daysOfWeekDisabled: [],
18908 singleMode : false,
18910 UTCDate: function()
18912 return new Date(Date.UTC.apply(Date, arguments));
18915 UTCToday: function()
18917 var today = new Date();
18918 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18921 getDate: function() {
18922 var d = this.getUTCDate();
18923 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18926 getUTCDate: function() {
18930 setDate: function(d) {
18931 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18934 setUTCDate: function(d) {
18936 this.setValue(this.formatDate(this.date));
18939 onRender: function(ct, position)
18942 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18944 this.language = this.language || 'en';
18945 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18946 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18948 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18949 this.format = this.format || 'm/d/y';
18950 this.isInline = false;
18951 this.isInput = true;
18952 this.component = this.el.select('.add-on', true).first() || false;
18953 this.component = (this.component && this.component.length === 0) ? false : this.component;
18954 this.hasInput = this.component && this.inputEl().length;
18956 if (typeof(this.minViewMode === 'string')) {
18957 switch (this.minViewMode) {
18959 this.minViewMode = 1;
18962 this.minViewMode = 2;
18965 this.minViewMode = 0;
18970 if (typeof(this.viewMode === 'string')) {
18971 switch (this.viewMode) {
18984 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18986 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18988 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18990 this.picker().on('mousedown', this.onMousedown, this);
18991 this.picker().on('click', this.onClick, this);
18993 this.picker().addClass('datepicker-dropdown');
18995 this.startViewMode = this.viewMode;
18997 if(this.singleMode){
18998 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18999 v.setVisibilityMode(Roo.Element.DISPLAY);
19003 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19004 v.setStyle('width', '189px');
19008 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19009 if(!this.calendarWeeks){
19014 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19015 v.attr('colspan', function(i, val){
19016 return parseInt(val) + 1;
19021 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19023 this.setStartDate(this.startDate);
19024 this.setEndDate(this.endDate);
19026 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19033 if(this.isInline) {
19038 picker : function()
19040 return this.pickerEl;
19041 // return this.el.select('.datepicker', true).first();
19044 fillDow: function()
19046 var dowCnt = this.weekStart;
19055 if(this.calendarWeeks){
19063 while (dowCnt < this.weekStart + 7) {
19067 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19071 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19074 fillMonths: function()
19077 var months = this.picker().select('>.datepicker-months td', true).first();
19079 months.dom.innerHTML = '';
19085 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19088 months.createChild(month);
19095 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;
19097 if (this.date < this.startDate) {
19098 this.viewDate = new Date(this.startDate);
19099 } else if (this.date > this.endDate) {
19100 this.viewDate = new Date(this.endDate);
19102 this.viewDate = new Date(this.date);
19110 var d = new Date(this.viewDate),
19111 year = d.getUTCFullYear(),
19112 month = d.getUTCMonth(),
19113 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19114 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19115 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19116 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19117 currentDate = this.date && this.date.valueOf(),
19118 today = this.UTCToday();
19120 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19122 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19124 // this.picker.select('>tfoot th.today').
19125 // .text(dates[this.language].today)
19126 // .toggle(this.todayBtn !== false);
19128 this.updateNavArrows();
19131 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19133 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19135 prevMonth.setUTCDate(day);
19137 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19139 var nextMonth = new Date(prevMonth);
19141 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19143 nextMonth = nextMonth.valueOf();
19145 var fillMonths = false;
19147 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19149 while(prevMonth.valueOf() <= nextMonth) {
19152 if (prevMonth.getUTCDay() === this.weekStart) {
19154 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19162 if(this.calendarWeeks){
19163 // ISO 8601: First week contains first thursday.
19164 // ISO also states week starts on Monday, but we can be more abstract here.
19166 // Start of current week: based on weekstart/current date
19167 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19168 // Thursday of this week
19169 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19170 // First Thursday of year, year from thursday
19171 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19172 // Calendar week: ms between thursdays, div ms per day, div 7 days
19173 calWeek = (th - yth) / 864e5 / 7 + 1;
19175 fillMonths.cn.push({
19183 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19185 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19188 if (this.todayHighlight &&
19189 prevMonth.getUTCFullYear() == today.getFullYear() &&
19190 prevMonth.getUTCMonth() == today.getMonth() &&
19191 prevMonth.getUTCDate() == today.getDate()) {
19192 clsName += ' today';
19195 if (currentDate && prevMonth.valueOf() === currentDate) {
19196 clsName += ' active';
19199 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19200 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19201 clsName += ' disabled';
19204 fillMonths.cn.push({
19206 cls: 'day ' + clsName,
19207 html: prevMonth.getDate()
19210 prevMonth.setDate(prevMonth.getDate()+1);
19213 var currentYear = this.date && this.date.getUTCFullYear();
19214 var currentMonth = this.date && this.date.getUTCMonth();
19216 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19218 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19219 v.removeClass('active');
19221 if(currentYear === year && k === currentMonth){
19222 v.addClass('active');
19225 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19226 v.addClass('disabled');
19232 year = parseInt(year/10, 10) * 10;
19234 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19236 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19239 for (var i = -1; i < 11; i++) {
19240 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19242 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19250 showMode: function(dir)
19253 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19256 Roo.each(this.picker().select('>div',true).elements, function(v){
19257 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19260 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19265 if(this.isInline) {
19269 this.picker().removeClass(['bottom', 'top']);
19271 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19273 * place to the top of element!
19277 this.picker().addClass('top');
19278 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19283 this.picker().addClass('bottom');
19285 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19288 parseDate : function(value)
19290 if(!value || value instanceof Date){
19293 var v = Date.parseDate(value, this.format);
19294 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19295 v = Date.parseDate(value, 'Y-m-d');
19297 if(!v && this.altFormats){
19298 if(!this.altFormatsArray){
19299 this.altFormatsArray = this.altFormats.split("|");
19301 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19302 v = Date.parseDate(value, this.altFormatsArray[i]);
19308 formatDate : function(date, fmt)
19310 return (!date || !(date instanceof Date)) ?
19311 date : date.dateFormat(fmt || this.format);
19314 onFocus : function()
19316 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19320 onBlur : function()
19322 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19324 var d = this.inputEl().getValue();
19331 showPopup : function()
19333 this.picker().show();
19337 this.fireEvent('showpopup', this, this.date);
19340 hidePopup : function()
19342 if(this.isInline) {
19345 this.picker().hide();
19346 this.viewMode = this.startViewMode;
19349 this.fireEvent('hidepopup', this, this.date);
19353 onMousedown: function(e)
19355 e.stopPropagation();
19356 e.preventDefault();
19361 Roo.bootstrap.DateField.superclass.keyup.call(this);
19365 setValue: function(v)
19367 if(this.fireEvent('beforeselect', this, v) !== false){
19368 var d = new Date(this.parseDate(v) ).clearTime();
19370 if(isNaN(d.getTime())){
19371 this.date = this.viewDate = '';
19372 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19376 v = this.formatDate(d);
19378 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19380 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19384 this.fireEvent('select', this, this.date);
19388 getValue: function()
19390 return this.formatDate(this.date);
19393 fireKey: function(e)
19395 if (!this.picker().isVisible()){
19396 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19402 var dateChanged = false,
19404 newDate, newViewDate;
19409 e.preventDefault();
19413 if (!this.keyboardNavigation) {
19416 dir = e.keyCode == 37 ? -1 : 1;
19419 newDate = this.moveYear(this.date, dir);
19420 newViewDate = this.moveYear(this.viewDate, dir);
19421 } else if (e.shiftKey){
19422 newDate = this.moveMonth(this.date, dir);
19423 newViewDate = this.moveMonth(this.viewDate, dir);
19425 newDate = new Date(this.date);
19426 newDate.setUTCDate(this.date.getUTCDate() + dir);
19427 newViewDate = new Date(this.viewDate);
19428 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19430 if (this.dateWithinRange(newDate)){
19431 this.date = newDate;
19432 this.viewDate = newViewDate;
19433 this.setValue(this.formatDate(this.date));
19435 e.preventDefault();
19436 dateChanged = true;
19441 if (!this.keyboardNavigation) {
19444 dir = e.keyCode == 38 ? -1 : 1;
19446 newDate = this.moveYear(this.date, dir);
19447 newViewDate = this.moveYear(this.viewDate, dir);
19448 } else if (e.shiftKey){
19449 newDate = this.moveMonth(this.date, dir);
19450 newViewDate = this.moveMonth(this.viewDate, dir);
19452 newDate = new Date(this.date);
19453 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19454 newViewDate = new Date(this.viewDate);
19455 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19457 if (this.dateWithinRange(newDate)){
19458 this.date = newDate;
19459 this.viewDate = newViewDate;
19460 this.setValue(this.formatDate(this.date));
19462 e.preventDefault();
19463 dateChanged = true;
19467 this.setValue(this.formatDate(this.date));
19469 e.preventDefault();
19472 this.setValue(this.formatDate(this.date));
19486 onClick: function(e)
19488 e.stopPropagation();
19489 e.preventDefault();
19491 var target = e.getTarget();
19493 if(target.nodeName.toLowerCase() === 'i'){
19494 target = Roo.get(target).dom.parentNode;
19497 var nodeName = target.nodeName;
19498 var className = target.className;
19499 var html = target.innerHTML;
19500 //Roo.log(nodeName);
19502 switch(nodeName.toLowerCase()) {
19504 switch(className) {
19510 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19511 switch(this.viewMode){
19513 this.viewDate = this.moveMonth(this.viewDate, dir);
19517 this.viewDate = this.moveYear(this.viewDate, dir);
19523 var date = new Date();
19524 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19526 this.setValue(this.formatDate(this.date));
19533 if (className.indexOf('disabled') < 0) {
19534 this.viewDate.setUTCDate(1);
19535 if (className.indexOf('month') > -1) {
19536 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19538 var year = parseInt(html, 10) || 0;
19539 this.viewDate.setUTCFullYear(year);
19543 if(this.singleMode){
19544 this.setValue(this.formatDate(this.viewDate));
19555 //Roo.log(className);
19556 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19557 var day = parseInt(html, 10) || 1;
19558 var year = this.viewDate.getUTCFullYear(),
19559 month = this.viewDate.getUTCMonth();
19561 if (className.indexOf('old') > -1) {
19568 } else if (className.indexOf('new') > -1) {
19576 //Roo.log([year,month,day]);
19577 this.date = this.UTCDate(year, month, day,0,0,0,0);
19578 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19580 //Roo.log(this.formatDate(this.date));
19581 this.setValue(this.formatDate(this.date));
19588 setStartDate: function(startDate)
19590 this.startDate = startDate || -Infinity;
19591 if (this.startDate !== -Infinity) {
19592 this.startDate = this.parseDate(this.startDate);
19595 this.updateNavArrows();
19598 setEndDate: function(endDate)
19600 this.endDate = endDate || Infinity;
19601 if (this.endDate !== Infinity) {
19602 this.endDate = this.parseDate(this.endDate);
19605 this.updateNavArrows();
19608 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19610 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19611 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19612 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19614 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19615 return parseInt(d, 10);
19618 this.updateNavArrows();
19621 updateNavArrows: function()
19623 if(this.singleMode){
19627 var d = new Date(this.viewDate),
19628 year = d.getUTCFullYear(),
19629 month = d.getUTCMonth();
19631 Roo.each(this.picker().select('.prev', true).elements, function(v){
19633 switch (this.viewMode) {
19636 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19642 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19649 Roo.each(this.picker().select('.next', true).elements, function(v){
19651 switch (this.viewMode) {
19654 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19660 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19668 moveMonth: function(date, dir)
19673 var new_date = new Date(date.valueOf()),
19674 day = new_date.getUTCDate(),
19675 month = new_date.getUTCMonth(),
19676 mag = Math.abs(dir),
19678 dir = dir > 0 ? 1 : -1;
19681 // If going back one month, make sure month is not current month
19682 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19684 return new_date.getUTCMonth() == month;
19686 // If going forward one month, make sure month is as expected
19687 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19689 return new_date.getUTCMonth() != new_month;
19691 new_month = month + dir;
19692 new_date.setUTCMonth(new_month);
19693 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19694 if (new_month < 0 || new_month > 11) {
19695 new_month = (new_month + 12) % 12;
19698 // For magnitudes >1, move one month at a time...
19699 for (var i=0; i<mag; i++) {
19700 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19701 new_date = this.moveMonth(new_date, dir);
19703 // ...then reset the day, keeping it in the new month
19704 new_month = new_date.getUTCMonth();
19705 new_date.setUTCDate(day);
19707 return new_month != new_date.getUTCMonth();
19710 // Common date-resetting loop -- if date is beyond end of month, make it
19713 new_date.setUTCDate(--day);
19714 new_date.setUTCMonth(new_month);
19719 moveYear: function(date, dir)
19721 return this.moveMonth(date, dir*12);
19724 dateWithinRange: function(date)
19726 return date >= this.startDate && date <= this.endDate;
19732 this.picker().remove();
19735 validateValue : function(value)
19737 if(this.getVisibilityEl().hasClass('hidden')){
19741 if(value.length < 1) {
19742 if(this.allowBlank){
19748 if(value.length < this.minLength){
19751 if(value.length > this.maxLength){
19755 var vt = Roo.form.VTypes;
19756 if(!vt[this.vtype](value, this)){
19760 if(typeof this.validator == "function"){
19761 var msg = this.validator(value);
19767 if(this.regex && !this.regex.test(value)){
19771 if(typeof(this.parseDate(value)) == 'undefined'){
19775 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19779 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19789 this.date = this.viewDate = '';
19791 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19796 Roo.apply(Roo.bootstrap.DateField, {
19807 html: '<i class="fa fa-arrow-left"/>'
19817 html: '<i class="fa fa-arrow-right"/>'
19859 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19860 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19861 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19862 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19863 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19876 navFnc: 'FullYear',
19881 navFnc: 'FullYear',
19886 Roo.apply(Roo.bootstrap.DateField, {
19890 cls: 'datepicker dropdown-menu roo-dynamic',
19894 cls: 'datepicker-days',
19898 cls: 'table-condensed',
19900 Roo.bootstrap.DateField.head,
19904 Roo.bootstrap.DateField.footer
19911 cls: 'datepicker-months',
19915 cls: 'table-condensed',
19917 Roo.bootstrap.DateField.head,
19918 Roo.bootstrap.DateField.content,
19919 Roo.bootstrap.DateField.footer
19926 cls: 'datepicker-years',
19930 cls: 'table-condensed',
19932 Roo.bootstrap.DateField.head,
19933 Roo.bootstrap.DateField.content,
19934 Roo.bootstrap.DateField.footer
19953 * @class Roo.bootstrap.TimeField
19954 * @extends Roo.bootstrap.Input
19955 * Bootstrap DateField class
19959 * Create a new TimeField
19960 * @param {Object} config The config object
19963 Roo.bootstrap.TimeField = function(config){
19964 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19968 * Fires when this field show.
19969 * @param {Roo.bootstrap.DateField} thisthis
19970 * @param {Mixed} date The date value
19975 * Fires when this field hide.
19976 * @param {Roo.bootstrap.DateField} this
19977 * @param {Mixed} date The date value
19982 * Fires when select a date.
19983 * @param {Roo.bootstrap.DateField} this
19984 * @param {Mixed} date The date value
19990 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19993 * @cfg {String} format
19994 * The default time format string which can be overriden for localization support. The format must be
19995 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19999 onRender: function(ct, position)
20002 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20004 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20006 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20008 this.pop = this.picker().select('>.datepicker-time',true).first();
20009 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20011 this.picker().on('mousedown', this.onMousedown, this);
20012 this.picker().on('click', this.onClick, this);
20014 this.picker().addClass('datepicker-dropdown');
20019 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20020 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20021 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20022 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20023 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20024 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20028 fireKey: function(e){
20029 if (!this.picker().isVisible()){
20030 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20036 e.preventDefault();
20044 this.onTogglePeriod();
20047 this.onIncrementMinutes();
20050 this.onDecrementMinutes();
20059 onClick: function(e) {
20060 e.stopPropagation();
20061 e.preventDefault();
20064 picker : function()
20066 return this.el.select('.datepicker', true).first();
20069 fillTime: function()
20071 var time = this.pop.select('tbody', true).first();
20073 time.dom.innerHTML = '';
20088 cls: 'hours-up glyphicon glyphicon-chevron-up'
20108 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20129 cls: 'timepicker-hour',
20144 cls: 'timepicker-minute',
20159 cls: 'btn btn-primary period',
20181 cls: 'hours-down glyphicon glyphicon-chevron-down'
20201 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20219 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20226 var hours = this.time.getHours();
20227 var minutes = this.time.getMinutes();
20240 hours = hours - 12;
20244 hours = '0' + hours;
20248 minutes = '0' + minutes;
20251 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20252 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20253 this.pop.select('button', true).first().dom.innerHTML = period;
20259 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20261 var cls = ['bottom'];
20263 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20270 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20275 this.picker().addClass(cls.join('-'));
20279 Roo.each(cls, function(c){
20281 _this.picker().setTop(_this.inputEl().getHeight());
20285 _this.picker().setTop(0 - _this.picker().getHeight());
20290 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20294 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20301 onFocus : function()
20303 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20307 onBlur : function()
20309 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20315 this.picker().show();
20320 this.fireEvent('show', this, this.date);
20325 this.picker().hide();
20328 this.fireEvent('hide', this, this.date);
20331 setTime : function()
20334 this.setValue(this.time.format(this.format));
20336 this.fireEvent('select', this, this.date);
20341 onMousedown: function(e){
20342 e.stopPropagation();
20343 e.preventDefault();
20346 onIncrementHours: function()
20348 Roo.log('onIncrementHours');
20349 this.time = this.time.add(Date.HOUR, 1);
20354 onDecrementHours: function()
20356 Roo.log('onDecrementHours');
20357 this.time = this.time.add(Date.HOUR, -1);
20361 onIncrementMinutes: function()
20363 Roo.log('onIncrementMinutes');
20364 this.time = this.time.add(Date.MINUTE, 1);
20368 onDecrementMinutes: function()
20370 Roo.log('onDecrementMinutes');
20371 this.time = this.time.add(Date.MINUTE, -1);
20375 onTogglePeriod: function()
20377 Roo.log('onTogglePeriod');
20378 this.time = this.time.add(Date.HOUR, 12);
20385 Roo.apply(Roo.bootstrap.TimeField, {
20415 cls: 'btn btn-info ok',
20427 Roo.apply(Roo.bootstrap.TimeField, {
20431 cls: 'datepicker dropdown-menu',
20435 cls: 'datepicker-time',
20439 cls: 'table-condensed',
20441 Roo.bootstrap.TimeField.content,
20442 Roo.bootstrap.TimeField.footer
20461 * @class Roo.bootstrap.MonthField
20462 * @extends Roo.bootstrap.Input
20463 * Bootstrap MonthField class
20465 * @cfg {String} language default en
20468 * Create a new MonthField
20469 * @param {Object} config The config object
20472 Roo.bootstrap.MonthField = function(config){
20473 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20478 * Fires when this field show.
20479 * @param {Roo.bootstrap.MonthField} this
20480 * @param {Mixed} date The date value
20485 * Fires when this field hide.
20486 * @param {Roo.bootstrap.MonthField} this
20487 * @param {Mixed} date The date value
20492 * Fires when select a date.
20493 * @param {Roo.bootstrap.MonthField} this
20494 * @param {String} oldvalue The old value
20495 * @param {String} newvalue The new value
20501 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20503 onRender: function(ct, position)
20506 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20508 this.language = this.language || 'en';
20509 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20510 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20512 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20513 this.isInline = false;
20514 this.isInput = true;
20515 this.component = this.el.select('.add-on', true).first() || false;
20516 this.component = (this.component && this.component.length === 0) ? false : this.component;
20517 this.hasInput = this.component && this.inputEL().length;
20519 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20521 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20523 this.picker().on('mousedown', this.onMousedown, this);
20524 this.picker().on('click', this.onClick, this);
20526 this.picker().addClass('datepicker-dropdown');
20528 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20529 v.setStyle('width', '189px');
20536 if(this.isInline) {
20542 setValue: function(v, suppressEvent)
20544 var o = this.getValue();
20546 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20550 if(suppressEvent !== true){
20551 this.fireEvent('select', this, o, v);
20556 getValue: function()
20561 onClick: function(e)
20563 e.stopPropagation();
20564 e.preventDefault();
20566 var target = e.getTarget();
20568 if(target.nodeName.toLowerCase() === 'i'){
20569 target = Roo.get(target).dom.parentNode;
20572 var nodeName = target.nodeName;
20573 var className = target.className;
20574 var html = target.innerHTML;
20576 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20580 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20582 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20588 picker : function()
20590 return this.pickerEl;
20593 fillMonths: function()
20596 var months = this.picker().select('>.datepicker-months td', true).first();
20598 months.dom.innerHTML = '';
20604 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20607 months.createChild(month);
20616 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20617 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20620 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20621 e.removeClass('active');
20623 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20624 e.addClass('active');
20631 if(this.isInline) {
20635 this.picker().removeClass(['bottom', 'top']);
20637 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20639 * place to the top of element!
20643 this.picker().addClass('top');
20644 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20649 this.picker().addClass('bottom');
20651 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20654 onFocus : function()
20656 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20660 onBlur : function()
20662 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20664 var d = this.inputEl().getValue();
20673 this.picker().show();
20674 this.picker().select('>.datepicker-months', true).first().show();
20678 this.fireEvent('show', this, this.date);
20683 if(this.isInline) {
20686 this.picker().hide();
20687 this.fireEvent('hide', this, this.date);
20691 onMousedown: function(e)
20693 e.stopPropagation();
20694 e.preventDefault();
20699 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20703 fireKey: function(e)
20705 if (!this.picker().isVisible()){
20706 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20717 e.preventDefault();
20721 dir = e.keyCode == 37 ? -1 : 1;
20723 this.vIndex = this.vIndex + dir;
20725 if(this.vIndex < 0){
20729 if(this.vIndex > 11){
20733 if(isNaN(this.vIndex)){
20737 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20743 dir = e.keyCode == 38 ? -1 : 1;
20745 this.vIndex = this.vIndex + dir * 4;
20747 if(this.vIndex < 0){
20751 if(this.vIndex > 11){
20755 if(isNaN(this.vIndex)){
20759 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20764 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20765 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20769 e.preventDefault();
20772 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20773 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20789 this.picker().remove();
20794 Roo.apply(Roo.bootstrap.MonthField, {
20813 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20814 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20819 Roo.apply(Roo.bootstrap.MonthField, {
20823 cls: 'datepicker dropdown-menu roo-dynamic',
20827 cls: 'datepicker-months',
20831 cls: 'table-condensed',
20833 Roo.bootstrap.DateField.content
20853 * @class Roo.bootstrap.CheckBox
20854 * @extends Roo.bootstrap.Input
20855 * Bootstrap CheckBox class
20857 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20858 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20859 * @cfg {String} boxLabel The text that appears beside the checkbox
20860 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20861 * @cfg {Boolean} checked initnal the element
20862 * @cfg {Boolean} inline inline the element (default false)
20863 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20864 * @cfg {String} tooltip label tooltip
20867 * Create a new CheckBox
20868 * @param {Object} config The config object
20871 Roo.bootstrap.CheckBox = function(config){
20872 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20877 * Fires when the element is checked or unchecked.
20878 * @param {Roo.bootstrap.CheckBox} this This input
20879 * @param {Boolean} checked The new checked value
20884 * Fires when the element is click.
20885 * @param {Roo.bootstrap.CheckBox} this This input
20892 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20894 inputType: 'checkbox',
20903 // checkbox success does not make any sense really..
20908 getAutoCreate : function()
20910 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20916 cfg.cls = 'form-group ' + this.inputType; //input-group
20919 cfg.cls += ' ' + this.inputType + '-inline';
20925 type : this.inputType,
20926 value : this.inputValue,
20927 cls : 'roo-' + this.inputType, //'form-box',
20928 placeholder : this.placeholder || ''
20932 if(this.inputType != 'radio'){
20936 cls : 'roo-hidden-value',
20937 value : this.checked ? this.inputValue : this.valueOff
20942 if (this.weight) { // Validity check?
20943 cfg.cls += " " + this.inputType + "-" + this.weight;
20946 if (this.disabled) {
20947 input.disabled=true;
20951 input.checked = this.checked;
20956 input.name = this.name;
20958 if(this.inputType != 'radio'){
20959 hidden.name = this.name;
20960 input.name = '_hidden_' + this.name;
20965 input.cls += ' input-' + this.size;
20970 ['xs','sm','md','lg'].map(function(size){
20971 if (settings[size]) {
20972 cfg.cls += ' col-' + size + '-' + settings[size];
20976 var inputblock = input;
20978 if (this.before || this.after) {
20981 cls : 'input-group',
20986 inputblock.cn.push({
20988 cls : 'input-group-addon',
20993 inputblock.cn.push(input);
20995 if(this.inputType != 'radio'){
20996 inputblock.cn.push(hidden);
21000 inputblock.cn.push({
21002 cls : 'input-group-addon',
21008 var boxLabelCfg = false;
21014 //'for': id, // box label is handled by onclick - so no for...
21016 html: this.boxLabel
21019 boxLabelCfg.tooltip = this.tooltip;
21025 if (align ==='left' && this.fieldLabel.length) {
21026 // Roo.log("left and has label");
21031 cls : 'control-label',
21032 html : this.fieldLabel
21043 cfg.cn[1].cn.push(boxLabelCfg);
21046 if(this.labelWidth > 12){
21047 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21050 if(this.labelWidth < 13 && this.labelmd == 0){
21051 this.labelmd = this.labelWidth;
21054 if(this.labellg > 0){
21055 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21056 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21059 if(this.labelmd > 0){
21060 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21061 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21064 if(this.labelsm > 0){
21065 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21066 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21069 if(this.labelxs > 0){
21070 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21071 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21074 } else if ( this.fieldLabel.length) {
21075 // Roo.log(" label");
21079 tag: this.boxLabel ? 'span' : 'label',
21081 cls: 'control-label box-input-label',
21082 //cls : 'input-group-addon',
21083 html : this.fieldLabel
21090 cfg.cn.push(boxLabelCfg);
21095 // Roo.log(" no label && no align");
21096 cfg.cn = [ inputblock ] ;
21098 cfg.cn.push(boxLabelCfg);
21106 if(this.inputType != 'radio'){
21107 cfg.cn.push(hidden);
21115 * return the real input element.
21117 inputEl: function ()
21119 return this.el.select('input.roo-' + this.inputType,true).first();
21121 hiddenEl: function ()
21123 return this.el.select('input.roo-hidden-value',true).first();
21126 labelEl: function()
21128 return this.el.select('label.control-label',true).first();
21130 /* depricated... */
21134 return this.labelEl();
21137 boxLabelEl: function()
21139 return this.el.select('label.box-label',true).first();
21142 initEvents : function()
21144 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21146 this.inputEl().on('click', this.onClick, this);
21148 if (this.boxLabel) {
21149 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21152 this.startValue = this.getValue();
21155 Roo.bootstrap.CheckBox.register(this);
21159 onClick : function(e)
21161 if(this.fireEvent('click', this, e) !== false){
21162 this.setChecked(!this.checked);
21167 setChecked : function(state,suppressEvent)
21169 this.startValue = this.getValue();
21171 if(this.inputType == 'radio'){
21173 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21174 e.dom.checked = false;
21177 this.inputEl().dom.checked = true;
21179 this.inputEl().dom.value = this.inputValue;
21181 if(suppressEvent !== true){
21182 this.fireEvent('check', this, true);
21190 this.checked = state;
21192 this.inputEl().dom.checked = state;
21195 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21197 if(suppressEvent !== true){
21198 this.fireEvent('check', this, state);
21204 getValue : function()
21206 if(this.inputType == 'radio'){
21207 return this.getGroupValue();
21210 return this.hiddenEl().dom.value;
21214 getGroupValue : function()
21216 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21220 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21223 setValue : function(v,suppressEvent)
21225 if(this.inputType == 'radio'){
21226 this.setGroupValue(v, suppressEvent);
21230 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21235 setGroupValue : function(v, suppressEvent)
21237 this.startValue = this.getValue();
21239 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21240 e.dom.checked = false;
21242 if(e.dom.value == v){
21243 e.dom.checked = true;
21247 if(suppressEvent !== true){
21248 this.fireEvent('check', this, true);
21256 validate : function()
21258 if(this.getVisibilityEl().hasClass('hidden')){
21264 (this.inputType == 'radio' && this.validateRadio()) ||
21265 (this.inputType == 'checkbox' && this.validateCheckbox())
21271 this.markInvalid();
21275 validateRadio : function()
21277 if(this.getVisibilityEl().hasClass('hidden')){
21281 if(this.allowBlank){
21287 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21288 if(!e.dom.checked){
21300 validateCheckbox : function()
21303 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21304 //return (this.getValue() == this.inputValue) ? true : false;
21307 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21315 for(var i in group){
21316 if(group[i].el.isVisible(true)){
21324 for(var i in group){
21329 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21336 * Mark this field as valid
21338 markValid : function()
21342 this.fireEvent('valid', this);
21344 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21347 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21354 if(this.inputType == 'radio'){
21355 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21356 var fg = e.findParent('.form-group', false, true);
21357 if (Roo.bootstrap.version == 3) {
21358 fg.removeClass([_this.invalidClass, _this.validClass]);
21359 fg.addClass(_this.validClass);
21361 fg.removeClass(['is-valid', 'is-invalid']);
21362 fg.addClass('is-valid');
21370 var fg = this.el.findParent('.form-group', false, true);
21371 if (Roo.bootstrap.version == 3) {
21372 fg.removeClass([this.invalidClass, this.validClass]);
21373 fg.addClass(this.validClass);
21375 fg.removeClass(['is-valid', 'is-invalid']);
21376 fg.addClass('is-valid');
21381 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21387 for(var i in group){
21388 var fg = group[i].el.findParent('.form-group', false, true);
21389 if (Roo.bootstrap.version == 3) {
21390 fg.removeClass([this.invalidClass, this.validClass]);
21391 fg.addClass(this.validClass);
21393 fg.removeClass(['is-valid', 'is-invalid']);
21394 fg.addClass('is-valid');
21400 * Mark this field as invalid
21401 * @param {String} msg The validation message
21403 markInvalid : function(msg)
21405 if(this.allowBlank){
21411 this.fireEvent('invalid', this, msg);
21413 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21416 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21420 label.markInvalid();
21423 if(this.inputType == 'radio'){
21425 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21426 var fg = e.findParent('.form-group', false, true);
21427 if (Roo.bootstrap.version == 3) {
21428 fg.removeClass([_this.invalidClass, _this.validClass]);
21429 fg.addClass(_this.invalidClass);
21431 fg.removeClass(['is-invalid', 'is-valid']);
21432 fg.addClass('is-invalid');
21440 var fg = this.el.findParent('.form-group', false, true);
21441 if (Roo.bootstrap.version == 3) {
21442 fg.removeClass([_this.invalidClass, _this.validClass]);
21443 fg.addClass(_this.invalidClass);
21445 fg.removeClass(['is-invalid', 'is-valid']);
21446 fg.addClass('is-invalid');
21451 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21457 for(var i in group){
21458 var fg = group[i].el.findParent('.form-group', false, true);
21459 if (Roo.bootstrap.version == 3) {
21460 fg.removeClass([_this.invalidClass, _this.validClass]);
21461 fg.addClass(_this.invalidClass);
21463 fg.removeClass(['is-invalid', 'is-valid']);
21464 fg.addClass('is-invalid');
21470 clearInvalid : function()
21472 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21474 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21476 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21478 if (label && label.iconEl) {
21479 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21480 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21484 disable : function()
21486 if(this.inputType != 'radio'){
21487 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21494 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21495 _this.getActionEl().addClass(this.disabledClass);
21496 e.dom.disabled = true;
21500 this.disabled = true;
21501 this.fireEvent("disable", this);
21505 enable : function()
21507 if(this.inputType != 'radio'){
21508 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21515 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21516 _this.getActionEl().removeClass(this.disabledClass);
21517 e.dom.disabled = false;
21521 this.disabled = false;
21522 this.fireEvent("enable", this);
21526 setBoxLabel : function(v)
21531 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21537 Roo.apply(Roo.bootstrap.CheckBox, {
21542 * register a CheckBox Group
21543 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21545 register : function(checkbox)
21547 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21548 this.groups[checkbox.groupId] = {};
21551 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21555 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21559 * fetch a CheckBox Group based on the group ID
21560 * @param {string} the group ID
21561 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21563 get: function(groupId) {
21564 if (typeof(this.groups[groupId]) == 'undefined') {
21568 return this.groups[groupId] ;
21581 * @class Roo.bootstrap.Radio
21582 * @extends Roo.bootstrap.Component
21583 * Bootstrap Radio class
21584 * @cfg {String} boxLabel - the label associated
21585 * @cfg {String} value - the value of radio
21588 * Create a new Radio
21589 * @param {Object} config The config object
21591 Roo.bootstrap.Radio = function(config){
21592 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21596 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21602 getAutoCreate : function()
21606 cls : 'form-group radio',
21611 html : this.boxLabel
21619 initEvents : function()
21621 this.parent().register(this);
21623 this.el.on('click', this.onClick, this);
21627 onClick : function(e)
21629 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21630 this.setChecked(true);
21634 setChecked : function(state, suppressEvent)
21636 this.parent().setValue(this.value, suppressEvent);
21640 setBoxLabel : function(v)
21645 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21660 * @class Roo.bootstrap.SecurePass
21661 * @extends Roo.bootstrap.Input
21662 * Bootstrap SecurePass class
21666 * Create a new SecurePass
21667 * @param {Object} config The config object
21670 Roo.bootstrap.SecurePass = function (config) {
21671 // these go here, so the translation tool can replace them..
21673 PwdEmpty: "Please type a password, and then retype it to confirm.",
21674 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21675 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21676 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21677 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21678 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21679 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21680 TooWeak: "Your password is Too Weak."
21682 this.meterLabel = "Password strength:";
21683 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21684 this.meterClass = [
21685 "roo-password-meter-tooweak",
21686 "roo-password-meter-weak",
21687 "roo-password-meter-medium",
21688 "roo-password-meter-strong",
21689 "roo-password-meter-grey"
21694 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21697 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21699 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21701 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21702 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21703 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21704 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21705 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21706 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21707 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21717 * @cfg {String/Object} Label for the strength meter (defaults to
21718 * 'Password strength:')
21723 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21724 * ['Weak', 'Medium', 'Strong'])
21727 pwdStrengths: false,
21740 initEvents: function ()
21742 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21744 if (this.el.is('input[type=password]') && Roo.isSafari) {
21745 this.el.on('keydown', this.SafariOnKeyDown, this);
21748 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21751 onRender: function (ct, position)
21753 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21754 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21755 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21757 this.trigger.createChild({
21762 cls: 'roo-password-meter-grey col-xs-12',
21765 //width: this.meterWidth + 'px'
21769 cls: 'roo-password-meter-text'
21775 if (this.hideTrigger) {
21776 this.trigger.setDisplayed(false);
21778 this.setSize(this.width || '', this.height || '');
21781 onDestroy: function ()
21783 if (this.trigger) {
21784 this.trigger.removeAllListeners();
21785 this.trigger.remove();
21788 this.wrap.remove();
21790 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21793 checkStrength: function ()
21795 var pwd = this.inputEl().getValue();
21796 if (pwd == this._lastPwd) {
21801 if (this.ClientSideStrongPassword(pwd)) {
21803 } else if (this.ClientSideMediumPassword(pwd)) {
21805 } else if (this.ClientSideWeakPassword(pwd)) {
21811 Roo.log('strength1: ' + strength);
21813 //var pm = this.trigger.child('div/div/div').dom;
21814 var pm = this.trigger.child('div/div');
21815 pm.removeClass(this.meterClass);
21816 pm.addClass(this.meterClass[strength]);
21819 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21821 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21823 this._lastPwd = pwd;
21827 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21829 this._lastPwd = '';
21831 var pm = this.trigger.child('div/div');
21832 pm.removeClass(this.meterClass);
21833 pm.addClass('roo-password-meter-grey');
21836 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21839 this.inputEl().dom.type='password';
21842 validateValue: function (value)
21845 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21848 if (value.length == 0) {
21849 if (this.allowBlank) {
21850 this.clearInvalid();
21854 this.markInvalid(this.errors.PwdEmpty);
21855 this.errorMsg = this.errors.PwdEmpty;
21863 if ('[\x21-\x7e]*'.match(value)) {
21864 this.markInvalid(this.errors.PwdBadChar);
21865 this.errorMsg = this.errors.PwdBadChar;
21868 if (value.length < 6) {
21869 this.markInvalid(this.errors.PwdShort);
21870 this.errorMsg = this.errors.PwdShort;
21873 if (value.length > 16) {
21874 this.markInvalid(this.errors.PwdLong);
21875 this.errorMsg = this.errors.PwdLong;
21879 if (this.ClientSideStrongPassword(value)) {
21881 } else if (this.ClientSideMediumPassword(value)) {
21883 } else if (this.ClientSideWeakPassword(value)) {
21890 if (strength < 2) {
21891 //this.markInvalid(this.errors.TooWeak);
21892 this.errorMsg = this.errors.TooWeak;
21897 console.log('strength2: ' + strength);
21899 //var pm = this.trigger.child('div/div/div').dom;
21901 var pm = this.trigger.child('div/div');
21902 pm.removeClass(this.meterClass);
21903 pm.addClass(this.meterClass[strength]);
21905 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21907 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21909 this.errorMsg = '';
21913 CharacterSetChecks: function (type)
21916 this.fResult = false;
21919 isctype: function (character, type)
21922 case this.kCapitalLetter:
21923 if (character >= 'A' && character <= 'Z') {
21928 case this.kSmallLetter:
21929 if (character >= 'a' && character <= 'z') {
21935 if (character >= '0' && character <= '9') {
21940 case this.kPunctuation:
21941 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21952 IsLongEnough: function (pwd, size)
21954 return !(pwd == null || isNaN(size) || pwd.length < size);
21957 SpansEnoughCharacterSets: function (word, nb)
21959 if (!this.IsLongEnough(word, nb))
21964 var characterSetChecks = new Array(
21965 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21966 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21969 for (var index = 0; index < word.length; ++index) {
21970 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21971 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21972 characterSetChecks[nCharSet].fResult = true;
21979 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21980 if (characterSetChecks[nCharSet].fResult) {
21985 if (nCharSets < nb) {
21991 ClientSideStrongPassword: function (pwd)
21993 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21996 ClientSideMediumPassword: function (pwd)
21998 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22001 ClientSideWeakPassword: function (pwd)
22003 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22006 })//<script type="text/javascript">
22009 * Based Ext JS Library 1.1.1
22010 * Copyright(c) 2006-2007, Ext JS, LLC.
22016 * @class Roo.HtmlEditorCore
22017 * @extends Roo.Component
22018 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22020 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22023 Roo.HtmlEditorCore = function(config){
22026 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22031 * @event initialize
22032 * Fires when the editor is fully initialized (including the iframe)
22033 * @param {Roo.HtmlEditorCore} this
22038 * Fires when the editor is first receives the focus. Any insertion must wait
22039 * until after this event.
22040 * @param {Roo.HtmlEditorCore} this
22044 * @event beforesync
22045 * Fires before the textarea is updated with content from the editor iframe. Return false
22046 * to cancel the sync.
22047 * @param {Roo.HtmlEditorCore} this
22048 * @param {String} html
22052 * @event beforepush
22053 * Fires before the iframe editor is updated with content from the textarea. Return false
22054 * to cancel the push.
22055 * @param {Roo.HtmlEditorCore} this
22056 * @param {String} html
22061 * Fires when the textarea is updated with content from the editor iframe.
22062 * @param {Roo.HtmlEditorCore} this
22063 * @param {String} html
22068 * Fires when the iframe editor is updated with content from the textarea.
22069 * @param {Roo.HtmlEditorCore} this
22070 * @param {String} html
22075 * @event editorevent
22076 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22077 * @param {Roo.HtmlEditorCore} this
22083 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22085 // defaults : white / black...
22086 this.applyBlacklists();
22093 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22097 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22103 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22108 * @cfg {Number} height (in pixels)
22112 * @cfg {Number} width (in pixels)
22117 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22120 stylesheets: false,
22125 // private properties
22126 validationEvent : false,
22128 initialized : false,
22130 sourceEditMode : false,
22131 onFocus : Roo.emptyFn,
22133 hideMode:'offsets',
22137 // blacklist + whitelisted elements..
22144 * Protected method that will not generally be called directly. It
22145 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22146 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22148 getDocMarkup : function(){
22152 // inherit styels from page...??
22153 if (this.stylesheets === false) {
22155 Roo.get(document.head).select('style').each(function(node) {
22156 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22159 Roo.get(document.head).select('link').each(function(node) {
22160 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22163 } else if (!this.stylesheets.length) {
22165 st = '<style type="text/css">' +
22166 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22169 st = '<style type="text/css">' +
22174 st += '<style type="text/css">' +
22175 'IMG { cursor: pointer } ' +
22178 var cls = 'roo-htmleditor-body';
22180 if(this.bodyCls.length){
22181 cls += ' ' + this.bodyCls;
22184 return '<html><head>' + st +
22185 //<style type="text/css">' +
22186 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22188 ' </head><body class="' + cls + '"></body></html>';
22192 onRender : function(ct, position)
22195 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22196 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22199 this.el.dom.style.border = '0 none';
22200 this.el.dom.setAttribute('tabIndex', -1);
22201 this.el.addClass('x-hidden hide');
22205 if(Roo.isIE){ // fix IE 1px bogus margin
22206 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22210 this.frameId = Roo.id();
22214 var iframe = this.owner.wrap.createChild({
22216 cls: 'form-control', // bootstrap..
22218 name: this.frameId,
22219 frameBorder : 'no',
22220 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22225 this.iframe = iframe.dom;
22227 this.assignDocWin();
22229 this.doc.designMode = 'on';
22232 this.doc.write(this.getDocMarkup());
22236 var task = { // must defer to wait for browser to be ready
22238 //console.log("run task?" + this.doc.readyState);
22239 this.assignDocWin();
22240 if(this.doc.body || this.doc.readyState == 'complete'){
22242 this.doc.designMode="on";
22246 Roo.TaskMgr.stop(task);
22247 this.initEditor.defer(10, this);
22254 Roo.TaskMgr.start(task);
22259 onResize : function(w, h)
22261 Roo.log('resize: ' +w + ',' + h );
22262 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22266 if(typeof w == 'number'){
22268 this.iframe.style.width = w + 'px';
22270 if(typeof h == 'number'){
22272 this.iframe.style.height = h + 'px';
22274 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22281 * Toggles the editor between standard and source edit mode.
22282 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22284 toggleSourceEdit : function(sourceEditMode){
22286 this.sourceEditMode = sourceEditMode === true;
22288 if(this.sourceEditMode){
22290 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22293 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22294 //this.iframe.className = '';
22297 //this.setSize(this.owner.wrap.getSize());
22298 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22305 * Protected method that will not generally be called directly. If you need/want
22306 * custom HTML cleanup, this is the method you should override.
22307 * @param {String} html The HTML to be cleaned
22308 * return {String} The cleaned HTML
22310 cleanHtml : function(html){
22311 html = String(html);
22312 if(html.length > 5){
22313 if(Roo.isSafari){ // strip safari nonsense
22314 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22317 if(html == ' '){
22324 * HTML Editor -> Textarea
22325 * Protected method that will not generally be called directly. Syncs the contents
22326 * of the editor iframe with the textarea.
22328 syncValue : function(){
22329 if(this.initialized){
22330 var bd = (this.doc.body || this.doc.documentElement);
22331 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22332 var html = bd.innerHTML;
22334 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22335 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22337 html = '<div style="'+m[0]+'">' + html + '</div>';
22340 html = this.cleanHtml(html);
22341 // fix up the special chars.. normaly like back quotes in word...
22342 // however we do not want to do this with chinese..
22343 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
22345 var cc = match.charCodeAt();
22347 // Get the character value, handling surrogate pairs
22348 if (match.length == 2) {
22349 // It's a surrogate pair, calculate the Unicode code point
22350 var high = match.charCodeAt(0) - 0xD800;
22351 var low = match.charCodeAt(1) - 0xDC00;
22352 cc = (high * 0x400) + low + 0x10000;
22354 (cc >= 0x4E00 && cc < 0xA000 ) ||
22355 (cc >= 0x3400 && cc < 0x4E00 ) ||
22356 (cc >= 0xf900 && cc < 0xfb00 )
22361 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
22362 return "&#" + cc + ";";
22369 if(this.owner.fireEvent('beforesync', this, html) !== false){
22370 this.el.dom.value = html;
22371 this.owner.fireEvent('sync', this, html);
22377 * Protected method that will not generally be called directly. Pushes the value of the textarea
22378 * into the iframe editor.
22380 pushValue : function(){
22381 if(this.initialized){
22382 var v = this.el.dom.value.trim();
22384 // if(v.length < 1){
22388 if(this.owner.fireEvent('beforepush', this, v) !== false){
22389 var d = (this.doc.body || this.doc.documentElement);
22391 this.cleanUpPaste();
22392 this.el.dom.value = d.innerHTML;
22393 this.owner.fireEvent('push', this, v);
22399 deferFocus : function(){
22400 this.focus.defer(10, this);
22404 focus : function(){
22405 if(this.win && !this.sourceEditMode){
22412 assignDocWin: function()
22414 var iframe = this.iframe;
22417 this.doc = iframe.contentWindow.document;
22418 this.win = iframe.contentWindow;
22420 // if (!Roo.get(this.frameId)) {
22423 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22424 // this.win = Roo.get(this.frameId).dom.contentWindow;
22426 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22430 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22431 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22436 initEditor : function(){
22437 //console.log("INIT EDITOR");
22438 this.assignDocWin();
22442 this.doc.designMode="on";
22444 this.doc.write(this.getDocMarkup());
22447 var dbody = (this.doc.body || this.doc.documentElement);
22448 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22449 // this copies styles from the containing element into thsi one..
22450 // not sure why we need all of this..
22451 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22453 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22454 //ss['background-attachment'] = 'fixed'; // w3c
22455 dbody.bgProperties = 'fixed'; // ie
22456 //Roo.DomHelper.applyStyles(dbody, ss);
22457 Roo.EventManager.on(this.doc, {
22458 //'mousedown': this.onEditorEvent,
22459 'mouseup': this.onEditorEvent,
22460 'dblclick': this.onEditorEvent,
22461 'click': this.onEditorEvent,
22462 'keyup': this.onEditorEvent,
22467 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22469 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22470 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22472 this.initialized = true;
22474 this.owner.fireEvent('initialize', this);
22479 onDestroy : function(){
22485 //for (var i =0; i < this.toolbars.length;i++) {
22486 // // fixme - ask toolbars for heights?
22487 // this.toolbars[i].onDestroy();
22490 //this.wrap.dom.innerHTML = '';
22491 //this.wrap.remove();
22496 onFirstFocus : function(){
22498 this.assignDocWin();
22501 this.activated = true;
22504 if(Roo.isGecko){ // prevent silly gecko errors
22506 var s = this.win.getSelection();
22507 if(!s.focusNode || s.focusNode.nodeType != 3){
22508 var r = s.getRangeAt(0);
22509 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22514 this.execCmd('useCSS', true);
22515 this.execCmd('styleWithCSS', false);
22518 this.owner.fireEvent('activate', this);
22522 adjustFont: function(btn){
22523 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22524 //if(Roo.isSafari){ // safari
22527 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22528 if(Roo.isSafari){ // safari
22529 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22530 v = (v < 10) ? 10 : v;
22531 v = (v > 48) ? 48 : v;
22532 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22537 v = Math.max(1, v+adjust);
22539 this.execCmd('FontSize', v );
22542 onEditorEvent : function(e)
22544 this.owner.fireEvent('editorevent', this, e);
22545 // this.updateToolbar();
22546 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22549 insertTag : function(tg)
22551 // could be a bit smarter... -> wrap the current selected tRoo..
22552 if (tg.toLowerCase() == 'span' ||
22553 tg.toLowerCase() == 'code' ||
22554 tg.toLowerCase() == 'sup' ||
22555 tg.toLowerCase() == 'sub'
22558 range = this.createRange(this.getSelection());
22559 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22560 wrappingNode.appendChild(range.extractContents());
22561 range.insertNode(wrappingNode);
22568 this.execCmd("formatblock", tg);
22572 insertText : function(txt)
22576 var range = this.createRange();
22577 range.deleteContents();
22578 //alert(Sender.getAttribute('label'));
22580 range.insertNode(this.doc.createTextNode(txt));
22586 * Executes a Midas editor command on the editor document and performs necessary focus and
22587 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22588 * @param {String} cmd The Midas command
22589 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22591 relayCmd : function(cmd, value){
22593 this.execCmd(cmd, value);
22594 this.owner.fireEvent('editorevent', this);
22595 //this.updateToolbar();
22596 this.owner.deferFocus();
22600 * Executes a Midas editor command directly on the editor document.
22601 * For visual commands, you should use {@link #relayCmd} instead.
22602 * <b>This should only be called after the editor is initialized.</b>
22603 * @param {String} cmd The Midas command
22604 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22606 execCmd : function(cmd, value){
22607 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22614 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22616 * @param {String} text | dom node..
22618 insertAtCursor : function(text)
22621 if(!this.activated){
22627 var r = this.doc.selection.createRange();
22638 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22642 // from jquery ui (MIT licenced)
22644 var win = this.win;
22646 if (win.getSelection && win.getSelection().getRangeAt) {
22647 range = win.getSelection().getRangeAt(0);
22648 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22649 range.insertNode(node);
22650 } else if (win.document.selection && win.document.selection.createRange) {
22651 // no firefox support
22652 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22653 win.document.selection.createRange().pasteHTML(txt);
22655 // no firefox support
22656 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22657 this.execCmd('InsertHTML', txt);
22666 mozKeyPress : function(e){
22668 var c = e.getCharCode(), cmd;
22671 c = String.fromCharCode(c).toLowerCase();
22685 this.cleanUpPaste.defer(100, this);
22693 e.preventDefault();
22701 fixKeys : function(){ // load time branching for fastest keydown performance
22703 return function(e){
22704 var k = e.getKey(), r;
22707 r = this.doc.selection.createRange();
22710 r.pasteHTML('    ');
22717 r = this.doc.selection.createRange();
22719 var target = r.parentElement();
22720 if(!target || target.tagName.toLowerCase() != 'li'){
22722 r.pasteHTML('<br />');
22728 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22729 this.cleanUpPaste.defer(100, this);
22735 }else if(Roo.isOpera){
22736 return function(e){
22737 var k = e.getKey();
22741 this.execCmd('InsertHTML','    ');
22744 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22745 this.cleanUpPaste.defer(100, this);
22750 }else if(Roo.isSafari){
22751 return function(e){
22752 var k = e.getKey();
22756 this.execCmd('InsertText','\t');
22760 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22761 this.cleanUpPaste.defer(100, this);
22769 getAllAncestors: function()
22771 var p = this.getSelectedNode();
22774 a.push(p); // push blank onto stack..
22775 p = this.getParentElement();
22779 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22783 a.push(this.doc.body);
22787 lastSelNode : false,
22790 getSelection : function()
22792 this.assignDocWin();
22793 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22796 getSelectedNode: function()
22798 // this may only work on Gecko!!!
22800 // should we cache this!!!!
22805 var range = this.createRange(this.getSelection()).cloneRange();
22808 var parent = range.parentElement();
22810 var testRange = range.duplicate();
22811 testRange.moveToElementText(parent);
22812 if (testRange.inRange(range)) {
22815 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22818 parent = parent.parentElement;
22823 // is ancestor a text element.
22824 var ac = range.commonAncestorContainer;
22825 if (ac.nodeType == 3) {
22826 ac = ac.parentNode;
22829 var ar = ac.childNodes;
22832 var other_nodes = [];
22833 var has_other_nodes = false;
22834 for (var i=0;i<ar.length;i++) {
22835 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22838 // fullly contained node.
22840 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22845 // probably selected..
22846 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22847 other_nodes.push(ar[i]);
22851 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22856 has_other_nodes = true;
22858 if (!nodes.length && other_nodes.length) {
22859 nodes= other_nodes;
22861 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22867 createRange: function(sel)
22869 // this has strange effects when using with
22870 // top toolbar - not sure if it's a great idea.
22871 //this.editor.contentWindow.focus();
22872 if (typeof sel != "undefined") {
22874 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22876 return this.doc.createRange();
22879 return this.doc.createRange();
22882 getParentElement: function()
22885 this.assignDocWin();
22886 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22888 var range = this.createRange(sel);
22891 var p = range.commonAncestorContainer;
22892 while (p.nodeType == 3) { // text node
22903 * Range intersection.. the hard stuff...
22907 * [ -- selected range --- ]
22911 * if end is before start or hits it. fail.
22912 * if start is after end or hits it fail.
22914 * if either hits (but other is outside. - then it's not
22920 // @see http://www.thismuchiknow.co.uk/?p=64.
22921 rangeIntersectsNode : function(range, node)
22923 var nodeRange = node.ownerDocument.createRange();
22925 nodeRange.selectNode(node);
22927 nodeRange.selectNodeContents(node);
22930 var rangeStartRange = range.cloneRange();
22931 rangeStartRange.collapse(true);
22933 var rangeEndRange = range.cloneRange();
22934 rangeEndRange.collapse(false);
22936 var nodeStartRange = nodeRange.cloneRange();
22937 nodeStartRange.collapse(true);
22939 var nodeEndRange = nodeRange.cloneRange();
22940 nodeEndRange.collapse(false);
22942 return rangeStartRange.compareBoundaryPoints(
22943 Range.START_TO_START, nodeEndRange) == -1 &&
22944 rangeEndRange.compareBoundaryPoints(
22945 Range.START_TO_START, nodeStartRange) == 1;
22949 rangeCompareNode : function(range, node)
22951 var nodeRange = node.ownerDocument.createRange();
22953 nodeRange.selectNode(node);
22955 nodeRange.selectNodeContents(node);
22959 range.collapse(true);
22961 nodeRange.collapse(true);
22963 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22964 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22966 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22968 var nodeIsBefore = ss == 1;
22969 var nodeIsAfter = ee == -1;
22971 if (nodeIsBefore && nodeIsAfter) {
22974 if (!nodeIsBefore && nodeIsAfter) {
22975 return 1; //right trailed.
22978 if (nodeIsBefore && !nodeIsAfter) {
22979 return 2; // left trailed.
22985 // private? - in a new class?
22986 cleanUpPaste : function()
22988 // cleans up the whole document..
22989 Roo.log('cleanuppaste');
22991 this.cleanUpChildren(this.doc.body);
22992 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22993 if (clean != this.doc.body.innerHTML) {
22994 this.doc.body.innerHTML = clean;
22999 cleanWordChars : function(input) {// change the chars to hex code
23000 var he = Roo.HtmlEditorCore;
23002 var output = input;
23003 Roo.each(he.swapCodes, function(sw) {
23004 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
23006 output = output.replace(swapper, sw[1]);
23013 cleanUpChildren : function (n)
23015 if (!n.childNodes.length) {
23018 for (var i = n.childNodes.length-1; i > -1 ; i--) {
23019 this.cleanUpChild(n.childNodes[i]);
23026 cleanUpChild : function (node)
23029 //console.log(node);
23030 if (node.nodeName == "#text") {
23031 // clean up silly Windows -- stuff?
23034 if (node.nodeName == "#comment") {
23035 node.parentNode.removeChild(node);
23036 // clean up silly Windows -- stuff?
23039 var lcname = node.tagName.toLowerCase();
23040 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23041 // whitelist of tags..
23043 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23045 node.parentNode.removeChild(node);
23050 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23052 // spans with no attributes - just remove them..
23053 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
23054 remove_keep_children = true;
23057 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23058 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23060 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23061 // remove_keep_children = true;
23064 if (remove_keep_children) {
23065 this.cleanUpChildren(node);
23066 // inserts everything just before this node...
23067 while (node.childNodes.length) {
23068 var cn = node.childNodes[0];
23069 node.removeChild(cn);
23070 node.parentNode.insertBefore(cn, node);
23072 node.parentNode.removeChild(node);
23076 if (!node.attributes || !node.attributes.length) {
23081 this.cleanUpChildren(node);
23085 function cleanAttr(n,v)
23088 if (v.match(/^\./) || v.match(/^\//)) {
23091 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23094 if (v.match(/^#/)) {
23097 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23098 node.removeAttribute(n);
23102 var cwhite = this.cwhite;
23103 var cblack = this.cblack;
23105 function cleanStyle(n,v)
23107 if (v.match(/expression/)) { //XSS?? should we even bother..
23108 node.removeAttribute(n);
23112 var parts = v.split(/;/);
23115 Roo.each(parts, function(p) {
23116 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23120 var l = p.split(':').shift().replace(/\s+/g,'');
23121 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23123 if ( cwhite.length && cblack.indexOf(l) > -1) {
23124 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23125 //node.removeAttribute(n);
23129 // only allow 'c whitelisted system attributes'
23130 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23131 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23132 //node.removeAttribute(n);
23142 if (clean.length) {
23143 node.setAttribute(n, clean.join(';'));
23145 node.removeAttribute(n);
23151 for (var i = node.attributes.length-1; i > -1 ; i--) {
23152 var a = node.attributes[i];
23155 if (a.name.toLowerCase().substr(0,2)=='on') {
23156 node.removeAttribute(a.name);
23159 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23160 node.removeAttribute(a.name);
23163 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23164 cleanAttr(a.name,a.value); // fixme..
23167 if (a.name == 'style') {
23168 cleanStyle(a.name,a.value);
23171 /// clean up MS crap..
23172 // tecnically this should be a list of valid class'es..
23175 if (a.name == 'class') {
23176 if (a.value.match(/^Mso/)) {
23177 node.removeAttribute('class');
23180 if (a.value.match(/^body$/)) {
23181 node.removeAttribute('class');
23192 this.cleanUpChildren(node);
23198 * Clean up MS wordisms...
23200 cleanWord : function(node)
23203 this.cleanWord(this.doc.body);
23208 node.nodeName == 'SPAN' &&
23209 !node.hasAttributes() &&
23210 node.childNodes.length == 1 &&
23211 node.firstChild.nodeName == "#text"
23213 var textNode = node.firstChild;
23214 node.removeChild(textNode);
23215 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
23216 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
23218 node.parentNode.insertBefore(textNode, node);
23219 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
23220 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
23222 node.parentNode.removeChild(node);
23225 if (node.nodeName == "#text") {
23226 // clean up silly Windows -- stuff?
23229 if (node.nodeName == "#comment") {
23230 node.parentNode.removeChild(node);
23231 // clean up silly Windows -- stuff?
23235 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23236 node.parentNode.removeChild(node);
23239 //Roo.log(node.tagName);
23240 // remove - but keep children..
23241 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
23242 //Roo.log('-- removed');
23243 while (node.childNodes.length) {
23244 var cn = node.childNodes[0];
23245 node.removeChild(cn);
23246 node.parentNode.insertBefore(cn, node);
23247 // move node to parent - and clean it..
23248 this.cleanWord(cn);
23250 node.parentNode.removeChild(node);
23251 /// no need to iterate chidlren = it's got none..
23252 //this.iterateChildren(node, this.cleanWord);
23256 if (node.className.length) {
23258 var cn = node.className.split(/\W+/);
23260 Roo.each(cn, function(cls) {
23261 if (cls.match(/Mso[a-zA-Z]+/)) {
23266 node.className = cna.length ? cna.join(' ') : '';
23268 node.removeAttribute("class");
23272 if (node.hasAttribute("lang")) {
23273 node.removeAttribute("lang");
23276 if (node.hasAttribute("style")) {
23278 var styles = node.getAttribute("style").split(";");
23280 Roo.each(styles, function(s) {
23281 if (!s.match(/:/)) {
23284 var kv = s.split(":");
23285 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23288 // what ever is left... we allow.
23291 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23292 if (!nstyle.length) {
23293 node.removeAttribute('style');
23296 this.iterateChildren(node, this.cleanWord);
23302 * iterateChildren of a Node, calling fn each time, using this as the scole..
23303 * @param {DomNode} node node to iterate children of.
23304 * @param {Function} fn method of this class to call on each item.
23306 iterateChildren : function(node, fn)
23308 if (!node.childNodes.length) {
23311 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23312 fn.call(this, node.childNodes[i])
23318 * cleanTableWidths.
23320 * Quite often pasting from word etc.. results in tables with column and widths.
23321 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23324 cleanTableWidths : function(node)
23329 this.cleanTableWidths(this.doc.body);
23334 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23337 Roo.log(node.tagName);
23338 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23339 this.iterateChildren(node, this.cleanTableWidths);
23342 if (node.hasAttribute('width')) {
23343 node.removeAttribute('width');
23347 if (node.hasAttribute("style")) {
23350 var styles = node.getAttribute("style").split(";");
23352 Roo.each(styles, function(s) {
23353 if (!s.match(/:/)) {
23356 var kv = s.split(":");
23357 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23360 // what ever is left... we allow.
23363 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23364 if (!nstyle.length) {
23365 node.removeAttribute('style');
23369 this.iterateChildren(node, this.cleanTableWidths);
23377 domToHTML : function(currentElement, depth, nopadtext) {
23379 depth = depth || 0;
23380 nopadtext = nopadtext || false;
23382 if (!currentElement) {
23383 return this.domToHTML(this.doc.body);
23386 //Roo.log(currentElement);
23388 var allText = false;
23389 var nodeName = currentElement.nodeName;
23390 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23392 if (nodeName == '#text') {
23394 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23399 if (nodeName != 'BODY') {
23402 // Prints the node tagName, such as <A>, <IMG>, etc
23405 for(i = 0; i < currentElement.attributes.length;i++) {
23407 var aname = currentElement.attributes.item(i).name;
23408 if (!currentElement.attributes.item(i).value.length) {
23411 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23414 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23423 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23426 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23431 // Traverse the tree
23433 var currentElementChild = currentElement.childNodes.item(i);
23434 var allText = true;
23435 var innerHTML = '';
23437 while (currentElementChild) {
23438 // Formatting code (indent the tree so it looks nice on the screen)
23439 var nopad = nopadtext;
23440 if (lastnode == 'SPAN') {
23444 if (currentElementChild.nodeName == '#text') {
23445 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23446 toadd = nopadtext ? toadd : toadd.trim();
23447 if (!nopad && toadd.length > 80) {
23448 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23450 innerHTML += toadd;
23453 currentElementChild = currentElement.childNodes.item(i);
23459 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23461 // Recursively traverse the tree structure of the child node
23462 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23463 lastnode = currentElementChild.nodeName;
23465 currentElementChild=currentElement.childNodes.item(i);
23471 // The remaining code is mostly for formatting the tree
23472 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23477 ret+= "</"+tagName+">";
23483 applyBlacklists : function()
23485 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23486 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23490 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23491 if (b.indexOf(tag) > -1) {
23494 this.white.push(tag);
23498 Roo.each(w, function(tag) {
23499 if (b.indexOf(tag) > -1) {
23502 if (this.white.indexOf(tag) > -1) {
23505 this.white.push(tag);
23510 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23511 if (w.indexOf(tag) > -1) {
23514 this.black.push(tag);
23518 Roo.each(b, function(tag) {
23519 if (w.indexOf(tag) > -1) {
23522 if (this.black.indexOf(tag) > -1) {
23525 this.black.push(tag);
23530 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23531 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23535 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23536 if (b.indexOf(tag) > -1) {
23539 this.cwhite.push(tag);
23543 Roo.each(w, function(tag) {
23544 if (b.indexOf(tag) > -1) {
23547 if (this.cwhite.indexOf(tag) > -1) {
23550 this.cwhite.push(tag);
23555 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23556 if (w.indexOf(tag) > -1) {
23559 this.cblack.push(tag);
23563 Roo.each(b, function(tag) {
23564 if (w.indexOf(tag) > -1) {
23567 if (this.cblack.indexOf(tag) > -1) {
23570 this.cblack.push(tag);
23575 setStylesheets : function(stylesheets)
23577 if(typeof(stylesheets) == 'string'){
23578 Roo.get(this.iframe.contentDocument.head).createChild({
23580 rel : 'stylesheet',
23589 Roo.each(stylesheets, function(s) {
23594 Roo.get(_this.iframe.contentDocument.head).createChild({
23596 rel : 'stylesheet',
23605 removeStylesheets : function()
23609 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23614 setStyle : function(style)
23616 Roo.get(this.iframe.contentDocument.head).createChild({
23625 // hide stuff that is not compatible
23639 * @event specialkey
23643 * @cfg {String} fieldClass @hide
23646 * @cfg {String} focusClass @hide
23649 * @cfg {String} autoCreate @hide
23652 * @cfg {String} inputType @hide
23655 * @cfg {String} invalidClass @hide
23658 * @cfg {String} invalidText @hide
23661 * @cfg {String} msgFx @hide
23664 * @cfg {String} validateOnBlur @hide
23668 Roo.HtmlEditorCore.white = [
23669 'area', 'br', 'img', 'input', 'hr', 'wbr',
23671 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23672 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23673 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23674 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23675 'table', 'ul', 'xmp',
23677 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23680 'dir', 'menu', 'ol', 'ul', 'dl',
23686 Roo.HtmlEditorCore.black = [
23687 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23689 'base', 'basefont', 'bgsound', 'blink', 'body',
23690 'frame', 'frameset', 'head', 'html', 'ilayer',
23691 'iframe', 'layer', 'link', 'meta', 'object',
23692 'script', 'style' ,'title', 'xml' // clean later..
23694 Roo.HtmlEditorCore.clean = [
23695 'script', 'style', 'title', 'xml'
23697 Roo.HtmlEditorCore.remove = [
23702 Roo.HtmlEditorCore.ablack = [
23706 Roo.HtmlEditorCore.aclean = [
23707 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23711 Roo.HtmlEditorCore.pwhite= [
23712 'http', 'https', 'mailto'
23715 // white listed style attributes.
23716 Roo.HtmlEditorCore.cwhite= [
23717 // 'text-align', /// default is to allow most things..
23723 // black listed style attributes.
23724 Roo.HtmlEditorCore.cblack= [
23725 // 'font-size' -- this can be set by the project
23729 Roo.HtmlEditorCore.swapCodes =[
23748 * @class Roo.bootstrap.HtmlEditor
23749 * @extends Roo.bootstrap.TextArea
23750 * Bootstrap HtmlEditor class
23753 * Create a new HtmlEditor
23754 * @param {Object} config The config object
23757 Roo.bootstrap.HtmlEditor = function(config){
23758 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23759 if (!this.toolbars) {
23760 this.toolbars = [];
23763 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23766 * @event initialize
23767 * Fires when the editor is fully initialized (including the iframe)
23768 * @param {HtmlEditor} this
23773 * Fires when the editor is first receives the focus. Any insertion must wait
23774 * until after this event.
23775 * @param {HtmlEditor} this
23779 * @event beforesync
23780 * Fires before the textarea is updated with content from the editor iframe. Return false
23781 * to cancel the sync.
23782 * @param {HtmlEditor} this
23783 * @param {String} html
23787 * @event beforepush
23788 * Fires before the iframe editor is updated with content from the textarea. Return false
23789 * to cancel the push.
23790 * @param {HtmlEditor} this
23791 * @param {String} html
23796 * Fires when the textarea is updated with content from the editor iframe.
23797 * @param {HtmlEditor} this
23798 * @param {String} html
23803 * Fires when the iframe editor is updated with content from the textarea.
23804 * @param {HtmlEditor} this
23805 * @param {String} html
23809 * @event editmodechange
23810 * Fires when the editor switches edit modes
23811 * @param {HtmlEditor} this
23812 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23814 editmodechange: true,
23816 * @event editorevent
23817 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23818 * @param {HtmlEditor} this
23822 * @event firstfocus
23823 * Fires when on first focus - needed by toolbars..
23824 * @param {HtmlEditor} this
23829 * Auto save the htmlEditor value as a file into Events
23830 * @param {HtmlEditor} this
23834 * @event savedpreview
23835 * preview the saved version of htmlEditor
23836 * @param {HtmlEditor} this
23843 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23847 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23852 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23857 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23862 * @cfg {Number} height (in pixels)
23866 * @cfg {Number} width (in pixels)
23871 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23874 stylesheets: false,
23879 // private properties
23880 validationEvent : false,
23882 initialized : false,
23885 onFocus : Roo.emptyFn,
23887 hideMode:'offsets',
23889 tbContainer : false,
23893 toolbarContainer :function() {
23894 return this.wrap.select('.x-html-editor-tb',true).first();
23898 * Protected method that will not generally be called directly. It
23899 * is called when the editor creates its toolbar. Override this method if you need to
23900 * add custom toolbar buttons.
23901 * @param {HtmlEditor} editor
23903 createToolbar : function(){
23904 Roo.log('renewing');
23905 Roo.log("create toolbars");
23907 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23908 this.toolbars[0].render(this.toolbarContainer());
23912 // if (!editor.toolbars || !editor.toolbars.length) {
23913 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23916 // for (var i =0 ; i < editor.toolbars.length;i++) {
23917 // editor.toolbars[i] = Roo.factory(
23918 // typeof(editor.toolbars[i]) == 'string' ?
23919 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23920 // Roo.bootstrap.HtmlEditor);
23921 // editor.toolbars[i].init(editor);
23927 onRender : function(ct, position)
23929 // Roo.log("Call onRender: " + this.xtype);
23931 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23933 this.wrap = this.inputEl().wrap({
23934 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23937 this.editorcore.onRender(ct, position);
23939 if (this.resizable) {
23940 this.resizeEl = new Roo.Resizable(this.wrap, {
23944 minHeight : this.height,
23945 height: this.height,
23946 handles : this.resizable,
23949 resize : function(r, w, h) {
23950 _t.onResize(w,h); // -something
23956 this.createToolbar(this);
23959 if(!this.width && this.resizable){
23960 this.setSize(this.wrap.getSize());
23962 if (this.resizeEl) {
23963 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23964 // should trigger onReize..
23970 onResize : function(w, h)
23972 Roo.log('resize: ' +w + ',' + h );
23973 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23977 if(this.inputEl() ){
23978 if(typeof w == 'number'){
23979 var aw = w - this.wrap.getFrameWidth('lr');
23980 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23983 if(typeof h == 'number'){
23984 var tbh = -11; // fixme it needs to tool bar size!
23985 for (var i =0; i < this.toolbars.length;i++) {
23986 // fixme - ask toolbars for heights?
23987 tbh += this.toolbars[i].el.getHeight();
23988 //if (this.toolbars[i].footer) {
23989 // tbh += this.toolbars[i].footer.el.getHeight();
23997 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23998 ah -= 5; // knock a few pixes off for look..
23999 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
24003 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
24004 this.editorcore.onResize(ew,eh);
24009 * Toggles the editor between standard and source edit mode.
24010 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24012 toggleSourceEdit : function(sourceEditMode)
24014 this.editorcore.toggleSourceEdit(sourceEditMode);
24016 if(this.editorcore.sourceEditMode){
24017 Roo.log('editor - showing textarea');
24020 // Roo.log(this.syncValue());
24022 this.inputEl().removeClass(['hide', 'x-hidden']);
24023 this.inputEl().dom.removeAttribute('tabIndex');
24024 this.inputEl().focus();
24026 Roo.log('editor - hiding textarea');
24028 // Roo.log(this.pushValue());
24031 this.inputEl().addClass(['hide', 'x-hidden']);
24032 this.inputEl().dom.setAttribute('tabIndex', -1);
24033 //this.deferFocus();
24036 if(this.resizable){
24037 this.setSize(this.wrap.getSize());
24040 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
24043 // private (for BoxComponent)
24044 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24046 // private (for BoxComponent)
24047 getResizeEl : function(){
24051 // private (for BoxComponent)
24052 getPositionEl : function(){
24057 initEvents : function(){
24058 this.originalValue = this.getValue();
24062 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24065 // markInvalid : Roo.emptyFn,
24067 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24070 // clearInvalid : Roo.emptyFn,
24072 setValue : function(v){
24073 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24074 this.editorcore.pushValue();
24079 deferFocus : function(){
24080 this.focus.defer(10, this);
24084 focus : function(){
24085 this.editorcore.focus();
24091 onDestroy : function(){
24097 for (var i =0; i < this.toolbars.length;i++) {
24098 // fixme - ask toolbars for heights?
24099 this.toolbars[i].onDestroy();
24102 this.wrap.dom.innerHTML = '';
24103 this.wrap.remove();
24108 onFirstFocus : function(){
24109 //Roo.log("onFirstFocus");
24110 this.editorcore.onFirstFocus();
24111 for (var i =0; i < this.toolbars.length;i++) {
24112 this.toolbars[i].onFirstFocus();
24118 syncValue : function()
24120 this.editorcore.syncValue();
24123 pushValue : function()
24125 this.editorcore.pushValue();
24129 // hide stuff that is not compatible
24143 * @event specialkey
24147 * @cfg {String} fieldClass @hide
24150 * @cfg {String} focusClass @hide
24153 * @cfg {String} autoCreate @hide
24156 * @cfg {String} inputType @hide
24160 * @cfg {String} invalidText @hide
24163 * @cfg {String} msgFx @hide
24166 * @cfg {String} validateOnBlur @hide
24175 Roo.namespace('Roo.bootstrap.htmleditor');
24177 * @class Roo.bootstrap.HtmlEditorToolbar1
24183 new Roo.bootstrap.HtmlEditor({
24186 new Roo.bootstrap.HtmlEditorToolbar1({
24187 disable : { fonts: 1 , format: 1, ..., ... , ...],
24193 * @cfg {Object} disable List of elements to disable..
24194 * @cfg {Array} btns List of additional buttons.
24198 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24201 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24204 Roo.apply(this, config);
24206 // default disabled, based on 'good practice'..
24207 this.disable = this.disable || {};
24208 Roo.applyIf(this.disable, {
24211 specialElements : true
24213 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24215 this.editor = config.editor;
24216 this.editorcore = config.editor.editorcore;
24218 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24220 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24221 // dont call parent... till later.
24223 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24228 editorcore : false,
24233 "h1","h2","h3","h4","h5","h6",
24235 "abbr", "acronym", "address", "cite", "samp", "var",
24239 onRender : function(ct, position)
24241 // Roo.log("Call onRender: " + this.xtype);
24243 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24245 this.el.dom.style.marginBottom = '0';
24247 var editorcore = this.editorcore;
24248 var editor= this.editor;
24251 var btn = function(id,cmd , toggle, handler, html){
24253 var event = toggle ? 'toggle' : 'click';
24258 xns: Roo.bootstrap,
24262 enableToggle:toggle !== false,
24264 pressed : toggle ? false : null,
24267 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24268 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24274 // var cb_box = function...
24279 xns: Roo.bootstrap,
24284 xns: Roo.bootstrap,
24288 Roo.each(this.formats, function(f) {
24289 style.menu.items.push({
24291 xns: Roo.bootstrap,
24292 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24297 editorcore.insertTag(this.tagname);
24304 children.push(style);
24306 btn('bold',false,true);
24307 btn('italic',false,true);
24308 btn('align-left', 'justifyleft',true);
24309 btn('align-center', 'justifycenter',true);
24310 btn('align-right' , 'justifyright',true);
24311 btn('link', false, false, function(btn) {
24312 //Roo.log("create link?");
24313 var url = prompt(this.createLinkText, this.defaultLinkValue);
24314 if(url && url != 'http:/'+'/'){
24315 this.editorcore.relayCmd('createlink', url);
24318 btn('list','insertunorderedlist',true);
24319 btn('pencil', false,true, function(btn){
24321 this.toggleSourceEdit(btn.pressed);
24324 if (this.editor.btns.length > 0) {
24325 for (var i = 0; i<this.editor.btns.length; i++) {
24326 children.push(this.editor.btns[i]);
24334 xns: Roo.bootstrap,
24339 xns: Roo.bootstrap,
24344 cog.menu.items.push({
24346 xns: Roo.bootstrap,
24347 html : Clean styles,
24352 editorcore.insertTag(this.tagname);
24361 this.xtype = 'NavSimplebar';
24363 for(var i=0;i< children.length;i++) {
24365 this.buttons.add(this.addxtypeChild(children[i]));
24369 editor.on('editorevent', this.updateToolbar, this);
24371 onBtnClick : function(id)
24373 this.editorcore.relayCmd(id);
24374 this.editorcore.focus();
24378 * Protected method that will not generally be called directly. It triggers
24379 * a toolbar update by reading the markup state of the current selection in the editor.
24381 updateToolbar: function(){
24383 if(!this.editorcore.activated){
24384 this.editor.onFirstFocus(); // is this neeed?
24388 var btns = this.buttons;
24389 var doc = this.editorcore.doc;
24390 btns.get('bold').setActive(doc.queryCommandState('bold'));
24391 btns.get('italic').setActive(doc.queryCommandState('italic'));
24392 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24394 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24395 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24396 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24398 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24399 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24402 var ans = this.editorcore.getAllAncestors();
24403 if (this.formatCombo) {
24406 var store = this.formatCombo.store;
24407 this.formatCombo.setValue("");
24408 for (var i =0; i < ans.length;i++) {
24409 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24411 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24419 // hides menus... - so this cant be on a menu...
24420 Roo.bootstrap.MenuMgr.hideAll();
24422 Roo.bootstrap.MenuMgr.hideAll();
24423 //this.editorsyncValue();
24425 onFirstFocus: function() {
24426 this.buttons.each(function(item){
24430 toggleSourceEdit : function(sourceEditMode){
24433 if(sourceEditMode){
24434 Roo.log("disabling buttons");
24435 this.buttons.each( function(item){
24436 if(item.cmd != 'pencil'){
24442 Roo.log("enabling buttons");
24443 if(this.editorcore.initialized){
24444 this.buttons.each( function(item){
24450 Roo.log("calling toggole on editor");
24451 // tell the editor that it's been pressed..
24452 this.editor.toggleSourceEdit(sourceEditMode);
24462 * @class Roo.bootstrap.Table.AbstractSelectionModel
24463 * @extends Roo.util.Observable
24464 * Abstract base class for grid SelectionModels. It provides the interface that should be
24465 * implemented by descendant classes. This class should not be directly instantiated.
24468 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24469 this.locked = false;
24470 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24474 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24475 /** @ignore Called by the grid automatically. Do not call directly. */
24476 init : function(grid){
24482 * Locks the selections.
24485 this.locked = true;
24489 * Unlocks the selections.
24491 unlock : function(){
24492 this.locked = false;
24496 * Returns true if the selections are locked.
24497 * @return {Boolean}
24499 isLocked : function(){
24500 return this.locked;
24504 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24505 * @class Roo.bootstrap.Table.RowSelectionModel
24506 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24507 * It supports multiple selections and keyboard selection/navigation.
24509 * @param {Object} config
24512 Roo.bootstrap.Table.RowSelectionModel = function(config){
24513 Roo.apply(this, config);
24514 this.selections = new Roo.util.MixedCollection(false, function(o){
24519 this.lastActive = false;
24523 * @event selectionchange
24524 * Fires when the selection changes
24525 * @param {SelectionModel} this
24527 "selectionchange" : true,
24529 * @event afterselectionchange
24530 * Fires after the selection changes (eg. by key press or clicking)
24531 * @param {SelectionModel} this
24533 "afterselectionchange" : true,
24535 * @event beforerowselect
24536 * Fires when a row is selected being selected, return false to cancel.
24537 * @param {SelectionModel} this
24538 * @param {Number} rowIndex The selected index
24539 * @param {Boolean} keepExisting False if other selections will be cleared
24541 "beforerowselect" : true,
24544 * Fires when a row is selected.
24545 * @param {SelectionModel} this
24546 * @param {Number} rowIndex The selected index
24547 * @param {Roo.data.Record} r The record
24549 "rowselect" : true,
24551 * @event rowdeselect
24552 * Fires when a row is deselected.
24553 * @param {SelectionModel} this
24554 * @param {Number} rowIndex The selected index
24556 "rowdeselect" : true
24558 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24559 this.locked = false;
24562 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24564 * @cfg {Boolean} singleSelect
24565 * True to allow selection of only one row at a time (defaults to false)
24567 singleSelect : false,
24570 initEvents : function()
24573 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24574 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24575 //}else{ // allow click to work like normal
24576 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24578 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24579 this.grid.on("rowclick", this.handleMouseDown, this);
24581 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24582 "up" : function(e){
24584 this.selectPrevious(e.shiftKey);
24585 }else if(this.last !== false && this.lastActive !== false){
24586 var last = this.last;
24587 this.selectRange(this.last, this.lastActive-1);
24588 this.grid.getView().focusRow(this.lastActive);
24589 if(last !== false){
24593 this.selectFirstRow();
24595 this.fireEvent("afterselectionchange", this);
24597 "down" : function(e){
24599 this.selectNext(e.shiftKey);
24600 }else if(this.last !== false && this.lastActive !== false){
24601 var last = this.last;
24602 this.selectRange(this.last, this.lastActive+1);
24603 this.grid.getView().focusRow(this.lastActive);
24604 if(last !== false){
24608 this.selectFirstRow();
24610 this.fireEvent("afterselectionchange", this);
24614 this.grid.store.on('load', function(){
24615 this.selections.clear();
24618 var view = this.grid.view;
24619 view.on("refresh", this.onRefresh, this);
24620 view.on("rowupdated", this.onRowUpdated, this);
24621 view.on("rowremoved", this.onRemove, this);
24626 onRefresh : function()
24628 var ds = this.grid.store, i, v = this.grid.view;
24629 var s = this.selections;
24630 s.each(function(r){
24631 if((i = ds.indexOfId(r.id)) != -1){
24640 onRemove : function(v, index, r){
24641 this.selections.remove(r);
24645 onRowUpdated : function(v, index, r){
24646 if(this.isSelected(r)){
24647 v.onRowSelect(index);
24653 * @param {Array} records The records to select
24654 * @param {Boolean} keepExisting (optional) True to keep existing selections
24656 selectRecords : function(records, keepExisting)
24659 this.clearSelections();
24661 var ds = this.grid.store;
24662 for(var i = 0, len = records.length; i < len; i++){
24663 this.selectRow(ds.indexOf(records[i]), true);
24668 * Gets the number of selected rows.
24671 getCount : function(){
24672 return this.selections.length;
24676 * Selects the first row in the grid.
24678 selectFirstRow : function(){
24683 * Select the last row.
24684 * @param {Boolean} keepExisting (optional) True to keep existing selections
24686 selectLastRow : function(keepExisting){
24687 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24688 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24692 * Selects the row immediately following the last selected row.
24693 * @param {Boolean} keepExisting (optional) True to keep existing selections
24695 selectNext : function(keepExisting)
24697 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24698 this.selectRow(this.last+1, keepExisting);
24699 this.grid.getView().focusRow(this.last);
24704 * Selects the row that precedes the last selected row.
24705 * @param {Boolean} keepExisting (optional) True to keep existing selections
24707 selectPrevious : function(keepExisting){
24709 this.selectRow(this.last-1, keepExisting);
24710 this.grid.getView().focusRow(this.last);
24715 * Returns the selected records
24716 * @return {Array} Array of selected records
24718 getSelections : function(){
24719 return [].concat(this.selections.items);
24723 * Returns the first selected record.
24726 getSelected : function(){
24727 return this.selections.itemAt(0);
24732 * Clears all selections.
24734 clearSelections : function(fast)
24740 var ds = this.grid.store;
24741 var s = this.selections;
24742 s.each(function(r){
24743 this.deselectRow(ds.indexOfId(r.id));
24747 this.selections.clear();
24754 * Selects all rows.
24756 selectAll : function(){
24760 this.selections.clear();
24761 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24762 this.selectRow(i, true);
24767 * Returns True if there is a selection.
24768 * @return {Boolean}
24770 hasSelection : function(){
24771 return this.selections.length > 0;
24775 * Returns True if the specified row is selected.
24776 * @param {Number/Record} record The record or index of the record to check
24777 * @return {Boolean}
24779 isSelected : function(index){
24780 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24781 return (r && this.selections.key(r.id) ? true : false);
24785 * Returns True if the specified record id is selected.
24786 * @param {String} id The id of record to check
24787 * @return {Boolean}
24789 isIdSelected : function(id){
24790 return (this.selections.key(id) ? true : false);
24795 handleMouseDBClick : function(e, t){
24799 handleMouseDown : function(e, t)
24801 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24802 if(this.isLocked() || rowIndex < 0 ){
24805 if(e.shiftKey && this.last !== false){
24806 var last = this.last;
24807 this.selectRange(last, rowIndex, e.ctrlKey);
24808 this.last = last; // reset the last
24812 var isSelected = this.isSelected(rowIndex);
24813 //Roo.log("select row:" + rowIndex);
24815 this.deselectRow(rowIndex);
24817 this.selectRow(rowIndex, true);
24821 if(e.button !== 0 && isSelected){
24822 alert('rowIndex 2: ' + rowIndex);
24823 view.focusRow(rowIndex);
24824 }else if(e.ctrlKey && isSelected){
24825 this.deselectRow(rowIndex);
24826 }else if(!isSelected){
24827 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24828 view.focusRow(rowIndex);
24832 this.fireEvent("afterselectionchange", this);
24835 handleDragableRowClick : function(grid, rowIndex, e)
24837 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24838 this.selectRow(rowIndex, false);
24839 grid.view.focusRow(rowIndex);
24840 this.fireEvent("afterselectionchange", this);
24845 * Selects multiple rows.
24846 * @param {Array} rows Array of the indexes of the row to select
24847 * @param {Boolean} keepExisting (optional) True to keep existing selections
24849 selectRows : function(rows, keepExisting){
24851 this.clearSelections();
24853 for(var i = 0, len = rows.length; i < len; i++){
24854 this.selectRow(rows[i], true);
24859 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24860 * @param {Number} startRow The index of the first row in the range
24861 * @param {Number} endRow The index of the last row in the range
24862 * @param {Boolean} keepExisting (optional) True to retain existing selections
24864 selectRange : function(startRow, endRow, keepExisting){
24869 this.clearSelections();
24871 if(startRow <= endRow){
24872 for(var i = startRow; i <= endRow; i++){
24873 this.selectRow(i, true);
24876 for(var i = startRow; i >= endRow; i--){
24877 this.selectRow(i, true);
24883 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24884 * @param {Number} startRow The index of the first row in the range
24885 * @param {Number} endRow The index of the last row in the range
24887 deselectRange : function(startRow, endRow, preventViewNotify){
24891 for(var i = startRow; i <= endRow; i++){
24892 this.deselectRow(i, preventViewNotify);
24898 * @param {Number} row The index of the row to select
24899 * @param {Boolean} keepExisting (optional) True to keep existing selections
24901 selectRow : function(index, keepExisting, preventViewNotify)
24903 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24906 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24907 if(!keepExisting || this.singleSelect){
24908 this.clearSelections();
24911 var r = this.grid.store.getAt(index);
24912 //console.log('selectRow - record id :' + r.id);
24914 this.selections.add(r);
24915 this.last = this.lastActive = index;
24916 if(!preventViewNotify){
24917 var proxy = new Roo.Element(
24918 this.grid.getRowDom(index)
24920 proxy.addClass('bg-info info');
24922 this.fireEvent("rowselect", this, index, r);
24923 this.fireEvent("selectionchange", this);
24929 * @param {Number} row The index of the row to deselect
24931 deselectRow : function(index, preventViewNotify)
24936 if(this.last == index){
24939 if(this.lastActive == index){
24940 this.lastActive = false;
24943 var r = this.grid.store.getAt(index);
24948 this.selections.remove(r);
24949 //.console.log('deselectRow - record id :' + r.id);
24950 if(!preventViewNotify){
24952 var proxy = new Roo.Element(
24953 this.grid.getRowDom(index)
24955 proxy.removeClass('bg-info info');
24957 this.fireEvent("rowdeselect", this, index);
24958 this.fireEvent("selectionchange", this);
24962 restoreLast : function(){
24964 this.last = this._last;
24969 acceptsNav : function(row, col, cm){
24970 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24974 onEditorKey : function(field, e){
24975 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24980 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24982 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24984 }else if(k == e.ENTER && !e.ctrlKey){
24988 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24990 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24992 }else if(k == e.ESC){
24996 g.startEditing(newCell[0], newCell[1]);
25002 * Ext JS Library 1.1.1
25003 * Copyright(c) 2006-2007, Ext JS, LLC.
25005 * Originally Released Under LGPL - original licence link has changed is not relivant.
25008 * <script type="text/javascript">
25012 * @class Roo.bootstrap.PagingToolbar
25013 * @extends Roo.bootstrap.NavSimplebar
25014 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
25016 * Create a new PagingToolbar
25017 * @param {Object} config The config object
25018 * @param {Roo.data.Store} store
25020 Roo.bootstrap.PagingToolbar = function(config)
25022 // old args format still supported... - xtype is prefered..
25023 // created from xtype...
25025 this.ds = config.dataSource;
25027 if (config.store && !this.ds) {
25028 this.store= Roo.factory(config.store, Roo.data);
25029 this.ds = this.store;
25030 this.ds.xmodule = this.xmodule || false;
25033 this.toolbarItems = [];
25034 if (config.items) {
25035 this.toolbarItems = config.items;
25038 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
25043 this.bind(this.ds);
25046 if (Roo.bootstrap.version == 4) {
25047 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
25049 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
25054 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
25056 * @cfg {Roo.data.Store} dataSource
25057 * The underlying data store providing the paged data
25060 * @cfg {String/HTMLElement/Element} container
25061 * container The id or element that will contain the toolbar
25064 * @cfg {Boolean} displayInfo
25065 * True to display the displayMsg (defaults to false)
25068 * @cfg {Number} pageSize
25069 * The number of records to display per page (defaults to 20)
25073 * @cfg {String} displayMsg
25074 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25076 displayMsg : 'Displaying {0} - {1} of {2}',
25078 * @cfg {String} emptyMsg
25079 * The message to display when no records are found (defaults to "No data to display")
25081 emptyMsg : 'No data to display',
25083 * Customizable piece of the default paging text (defaults to "Page")
25086 beforePageText : "Page",
25088 * Customizable piece of the default paging text (defaults to "of %0")
25091 afterPageText : "of {0}",
25093 * Customizable piece of the default paging text (defaults to "First Page")
25096 firstText : "First Page",
25098 * Customizable piece of the default paging text (defaults to "Previous Page")
25101 prevText : "Previous Page",
25103 * Customizable piece of the default paging text (defaults to "Next Page")
25106 nextText : "Next Page",
25108 * Customizable piece of the default paging text (defaults to "Last Page")
25111 lastText : "Last Page",
25113 * Customizable piece of the default paging text (defaults to "Refresh")
25116 refreshText : "Refresh",
25120 onRender : function(ct, position)
25122 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25123 this.navgroup.parentId = this.id;
25124 this.navgroup.onRender(this.el, null);
25125 // add the buttons to the navgroup
25127 if(this.displayInfo){
25128 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25129 this.displayEl = this.el.select('.x-paging-info', true).first();
25130 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25131 // this.displayEl = navel.el.select('span',true).first();
25137 Roo.each(_this.buttons, function(e){ // this might need to use render????
25138 Roo.factory(e).render(_this.el);
25142 Roo.each(_this.toolbarItems, function(e) {
25143 _this.navgroup.addItem(e);
25147 this.first = this.navgroup.addItem({
25148 tooltip: this.firstText,
25149 cls: "prev btn-outline-secondary",
25150 html : ' <i class="fa fa-step-backward"></i>',
25152 preventDefault: true,
25153 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25156 this.prev = this.navgroup.addItem({
25157 tooltip: this.prevText,
25158 cls: "prev btn-outline-secondary",
25159 html : ' <i class="fa fa-backward"></i>',
25161 preventDefault: true,
25162 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25164 //this.addSeparator();
25167 var field = this.navgroup.addItem( {
25169 cls : 'x-paging-position btn-outline-secondary',
25171 html : this.beforePageText +
25172 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25173 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25176 this.field = field.el.select('input', true).first();
25177 this.field.on("keydown", this.onPagingKeydown, this);
25178 this.field.on("focus", function(){this.dom.select();});
25181 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25182 //this.field.setHeight(18);
25183 //this.addSeparator();
25184 this.next = this.navgroup.addItem({
25185 tooltip: this.nextText,
25186 cls: "next btn-outline-secondary",
25187 html : ' <i class="fa fa-forward"></i>',
25189 preventDefault: true,
25190 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25192 this.last = this.navgroup.addItem({
25193 tooltip: this.lastText,
25194 html : ' <i class="fa fa-step-forward"></i>',
25195 cls: "next btn-outline-secondary",
25197 preventDefault: true,
25198 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25200 //this.addSeparator();
25201 this.loading = this.navgroup.addItem({
25202 tooltip: this.refreshText,
25203 cls: "btn-outline-secondary",
25204 html : ' <i class="fa fa-refresh"></i>',
25205 preventDefault: true,
25206 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25212 updateInfo : function(){
25213 if(this.displayEl){
25214 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25215 var msg = count == 0 ?
25219 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25221 this.displayEl.update(msg);
25226 onLoad : function(ds, r, o)
25228 this.cursor = o.params.start ? o.params.start : 0;
25230 var d = this.getPageData(),
25235 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25236 this.field.dom.value = ap;
25237 this.first.setDisabled(ap == 1);
25238 this.prev.setDisabled(ap == 1);
25239 this.next.setDisabled(ap == ps);
25240 this.last.setDisabled(ap == ps);
25241 this.loading.enable();
25246 getPageData : function(){
25247 var total = this.ds.getTotalCount();
25250 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25251 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25256 onLoadError : function(){
25257 this.loading.enable();
25261 onPagingKeydown : function(e){
25262 var k = e.getKey();
25263 var d = this.getPageData();
25265 var v = this.field.dom.value, pageNum;
25266 if(!v || isNaN(pageNum = parseInt(v, 10))){
25267 this.field.dom.value = d.activePage;
25270 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25271 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25274 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))
25276 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25277 this.field.dom.value = pageNum;
25278 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25281 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25283 var v = this.field.dom.value, pageNum;
25284 var increment = (e.shiftKey) ? 10 : 1;
25285 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25288 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25289 this.field.dom.value = d.activePage;
25292 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25294 this.field.dom.value = parseInt(v, 10) + increment;
25295 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25296 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25303 beforeLoad : function(){
25305 this.loading.disable();
25310 onClick : function(which){
25319 ds.load({params:{start: 0, limit: this.pageSize}});
25322 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25325 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25328 var total = ds.getTotalCount();
25329 var extra = total % this.pageSize;
25330 var lastStart = extra ? (total - extra) : total-this.pageSize;
25331 ds.load({params:{start: lastStart, limit: this.pageSize}});
25334 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25340 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25341 * @param {Roo.data.Store} store The data store to unbind
25343 unbind : function(ds){
25344 ds.un("beforeload", this.beforeLoad, this);
25345 ds.un("load", this.onLoad, this);
25346 ds.un("loadexception", this.onLoadError, this);
25347 ds.un("remove", this.updateInfo, this);
25348 ds.un("add", this.updateInfo, this);
25349 this.ds = undefined;
25353 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25354 * @param {Roo.data.Store} store The data store to bind
25356 bind : function(ds){
25357 ds.on("beforeload", this.beforeLoad, this);
25358 ds.on("load", this.onLoad, this);
25359 ds.on("loadexception", this.onLoadError, this);
25360 ds.on("remove", this.updateInfo, this);
25361 ds.on("add", this.updateInfo, this);
25372 * @class Roo.bootstrap.MessageBar
25373 * @extends Roo.bootstrap.Component
25374 * Bootstrap MessageBar class
25375 * @cfg {String} html contents of the MessageBar
25376 * @cfg {String} weight (info | success | warning | danger) default info
25377 * @cfg {String} beforeClass insert the bar before the given class
25378 * @cfg {Boolean} closable (true | false) default false
25379 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25382 * Create a new Element
25383 * @param {Object} config The config object
25386 Roo.bootstrap.MessageBar = function(config){
25387 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25390 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25396 beforeClass: 'bootstrap-sticky-wrap',
25398 getAutoCreate : function(){
25402 cls: 'alert alert-dismissable alert-' + this.weight,
25407 html: this.html || ''
25413 cfg.cls += ' alert-messages-fixed';
25427 onRender : function(ct, position)
25429 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25432 var cfg = Roo.apply({}, this.getAutoCreate());
25436 cfg.cls += ' ' + this.cls;
25439 cfg.style = this.style;
25441 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25443 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25446 this.el.select('>button.close').on('click', this.hide, this);
25452 if (!this.rendered) {
25458 this.fireEvent('show', this);
25464 if (!this.rendered) {
25470 this.fireEvent('hide', this);
25473 update : function()
25475 // var e = this.el.dom.firstChild;
25477 // if(this.closable){
25478 // e = e.nextSibling;
25481 // e.data = this.html || '';
25483 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25499 * @class Roo.bootstrap.Graph
25500 * @extends Roo.bootstrap.Component
25501 * Bootstrap Graph class
25505 @cfg {String} graphtype bar | vbar | pie
25506 @cfg {number} g_x coodinator | centre x (pie)
25507 @cfg {number} g_y coodinator | centre y (pie)
25508 @cfg {number} g_r radius (pie)
25509 @cfg {number} g_height height of the chart (respected by all elements in the set)
25510 @cfg {number} g_width width of the chart (respected by all elements in the set)
25511 @cfg {Object} title The title of the chart
25514 -opts (object) options for the chart
25516 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25517 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25519 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.
25520 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25522 o stretch (boolean)
25524 -opts (object) options for the pie
25527 o startAngle (number)
25528 o endAngle (number)
25532 * Create a new Input
25533 * @param {Object} config The config object
25536 Roo.bootstrap.Graph = function(config){
25537 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25543 * The img click event for the img.
25544 * @param {Roo.EventObject} e
25550 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25561 //g_colors: this.colors,
25568 getAutoCreate : function(){
25579 onRender : function(ct,position){
25582 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25584 if (typeof(Raphael) == 'undefined') {
25585 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25589 this.raphael = Raphael(this.el.dom);
25591 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25592 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25593 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25594 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25596 r.text(160, 10, "Single Series Chart").attr(txtattr);
25597 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25598 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25599 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25601 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25602 r.barchart(330, 10, 300, 220, data1);
25603 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25604 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25607 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25608 // r.barchart(30, 30, 560, 250, xdata, {
25609 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25610 // axis : "0 0 1 1",
25611 // axisxlabels : xdata
25612 // //yvalues : cols,
25615 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25617 // this.load(null,xdata,{
25618 // axis : "0 0 1 1",
25619 // axisxlabels : xdata
25624 load : function(graphtype,xdata,opts)
25626 this.raphael.clear();
25628 graphtype = this.graphtype;
25633 var r = this.raphael,
25634 fin = function () {
25635 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25637 fout = function () {
25638 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25640 pfin = function() {
25641 this.sector.stop();
25642 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25645 this.label[0].stop();
25646 this.label[0].attr({ r: 7.5 });
25647 this.label[1].attr({ "font-weight": 800 });
25650 pfout = function() {
25651 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25654 this.label[0].animate({ r: 5 }, 500, "bounce");
25655 this.label[1].attr({ "font-weight": 400 });
25661 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25664 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25667 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25668 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25670 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25677 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25682 setTitle: function(o)
25687 initEvents: function() {
25690 this.el.on('click', this.onClick, this);
25694 onClick : function(e)
25696 Roo.log('img onclick');
25697 this.fireEvent('click', this, e);
25709 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25712 * @class Roo.bootstrap.dash.NumberBox
25713 * @extends Roo.bootstrap.Component
25714 * Bootstrap NumberBox class
25715 * @cfg {String} headline Box headline
25716 * @cfg {String} content Box content
25717 * @cfg {String} icon Box icon
25718 * @cfg {String} footer Footer text
25719 * @cfg {String} fhref Footer href
25722 * Create a new NumberBox
25723 * @param {Object} config The config object
25727 Roo.bootstrap.dash.NumberBox = function(config){
25728 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25732 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25741 getAutoCreate : function(){
25745 cls : 'small-box ',
25753 cls : 'roo-headline',
25754 html : this.headline
25758 cls : 'roo-content',
25759 html : this.content
25773 cls : 'ion ' + this.icon
25782 cls : 'small-box-footer',
25783 href : this.fhref || '#',
25787 cfg.cn.push(footer);
25794 onRender : function(ct,position){
25795 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25802 setHeadline: function (value)
25804 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25807 setFooter: function (value, href)
25809 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25812 this.el.select('a.small-box-footer',true).first().attr('href', href);
25817 setContent: function (value)
25819 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25822 initEvents: function()
25836 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25839 * @class Roo.bootstrap.dash.TabBox
25840 * @extends Roo.bootstrap.Component
25841 * Bootstrap TabBox class
25842 * @cfg {String} title Title of the TabBox
25843 * @cfg {String} icon Icon of the TabBox
25844 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25845 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25848 * Create a new TabBox
25849 * @param {Object} config The config object
25853 Roo.bootstrap.dash.TabBox = function(config){
25854 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25859 * When a pane is added
25860 * @param {Roo.bootstrap.dash.TabPane} pane
25864 * @event activatepane
25865 * When a pane is activated
25866 * @param {Roo.bootstrap.dash.TabPane} pane
25868 "activatepane" : true
25876 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25881 tabScrollable : false,
25883 getChildContainer : function()
25885 return this.el.select('.tab-content', true).first();
25888 getAutoCreate : function(){
25892 cls: 'pull-left header',
25900 cls: 'fa ' + this.icon
25906 cls: 'nav nav-tabs pull-right',
25912 if(this.tabScrollable){
25919 cls: 'nav nav-tabs pull-right',
25930 cls: 'nav-tabs-custom',
25935 cls: 'tab-content no-padding',
25943 initEvents : function()
25945 //Roo.log('add add pane handler');
25946 this.on('addpane', this.onAddPane, this);
25949 * Updates the box title
25950 * @param {String} html to set the title to.
25952 setTitle : function(value)
25954 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25956 onAddPane : function(pane)
25958 this.panes.push(pane);
25959 //Roo.log('addpane');
25961 // tabs are rendere left to right..
25962 if(!this.showtabs){
25966 var ctr = this.el.select('.nav-tabs', true).first();
25969 var existing = ctr.select('.nav-tab',true);
25970 var qty = existing.getCount();;
25973 var tab = ctr.createChild({
25975 cls : 'nav-tab' + (qty ? '' : ' active'),
25983 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25986 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25988 pane.el.addClass('active');
25993 onTabClick : function(ev,un,ob,pane)
25995 //Roo.log('tab - prev default');
25996 ev.preventDefault();
25999 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
26000 pane.tab.addClass('active');
26001 //Roo.log(pane.title);
26002 this.getChildContainer().select('.tab-pane',true).removeClass('active');
26003 // technically we should have a deactivate event.. but maybe add later.
26004 // and it should not de-activate the selected tab...
26005 this.fireEvent('activatepane', pane);
26006 pane.el.addClass('active');
26007 pane.fireEvent('activate');
26012 getActivePane : function()
26015 Roo.each(this.panes, function(p) {
26016 if(p.el.hasClass('active')){
26037 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26039 * @class Roo.bootstrap.TabPane
26040 * @extends Roo.bootstrap.Component
26041 * Bootstrap TabPane class
26042 * @cfg {Boolean} active (false | true) Default false
26043 * @cfg {String} title title of panel
26047 * Create a new TabPane
26048 * @param {Object} config The config object
26051 Roo.bootstrap.dash.TabPane = function(config){
26052 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26058 * When a pane is activated
26059 * @param {Roo.bootstrap.dash.TabPane} pane
26066 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26071 // the tabBox that this is attached to.
26074 getAutoCreate : function()
26082 cfg.cls += ' active';
26087 initEvents : function()
26089 //Roo.log('trigger add pane handler');
26090 this.parent().fireEvent('addpane', this)
26094 * Updates the tab title
26095 * @param {String} html to set the title to.
26097 setTitle: function(str)
26103 this.tab.select('a', true).first().dom.innerHTML = str;
26120 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26123 * @class Roo.bootstrap.menu.Menu
26124 * @extends Roo.bootstrap.Component
26125 * Bootstrap Menu class - container for Menu
26126 * @cfg {String} html Text of the menu
26127 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26128 * @cfg {String} icon Font awesome icon
26129 * @cfg {String} pos Menu align to (top | bottom) default bottom
26133 * Create a new Menu
26134 * @param {Object} config The config object
26138 Roo.bootstrap.menu.Menu = function(config){
26139 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26143 * @event beforeshow
26144 * Fires before this menu is displayed
26145 * @param {Roo.bootstrap.menu.Menu} this
26149 * @event beforehide
26150 * Fires before this menu is hidden
26151 * @param {Roo.bootstrap.menu.Menu} this
26156 * Fires after this menu is displayed
26157 * @param {Roo.bootstrap.menu.Menu} this
26162 * Fires after this menu is hidden
26163 * @param {Roo.bootstrap.menu.Menu} this
26168 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26169 * @param {Roo.bootstrap.menu.Menu} this
26170 * @param {Roo.EventObject} e
26177 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26181 weight : 'default',
26186 getChildContainer : function() {
26187 if(this.isSubMenu){
26191 return this.el.select('ul.dropdown-menu', true).first();
26194 getAutoCreate : function()
26199 cls : 'roo-menu-text',
26207 cls : 'fa ' + this.icon
26218 cls : 'dropdown-button btn btn-' + this.weight,
26223 cls : 'dropdown-toggle btn btn-' + this.weight,
26233 cls : 'dropdown-menu'
26239 if(this.pos == 'top'){
26240 cfg.cls += ' dropup';
26243 if(this.isSubMenu){
26246 cls : 'dropdown-menu'
26253 onRender : function(ct, position)
26255 this.isSubMenu = ct.hasClass('dropdown-submenu');
26257 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26260 initEvents : function()
26262 if(this.isSubMenu){
26266 this.hidden = true;
26268 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26269 this.triggerEl.on('click', this.onTriggerPress, this);
26271 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26272 this.buttonEl.on('click', this.onClick, this);
26278 if(this.isSubMenu){
26282 return this.el.select('ul.dropdown-menu', true).first();
26285 onClick : function(e)
26287 this.fireEvent("click", this, e);
26290 onTriggerPress : function(e)
26292 if (this.isVisible()) {
26299 isVisible : function(){
26300 return !this.hidden;
26305 this.fireEvent("beforeshow", this);
26307 this.hidden = false;
26308 this.el.addClass('open');
26310 Roo.get(document).on("mouseup", this.onMouseUp, this);
26312 this.fireEvent("show", this);
26319 this.fireEvent("beforehide", this);
26321 this.hidden = true;
26322 this.el.removeClass('open');
26324 Roo.get(document).un("mouseup", this.onMouseUp);
26326 this.fireEvent("hide", this);
26329 onMouseUp : function()
26343 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26346 * @class Roo.bootstrap.menu.Item
26347 * @extends Roo.bootstrap.Component
26348 * Bootstrap MenuItem class
26349 * @cfg {Boolean} submenu (true | false) default false
26350 * @cfg {String} html text of the item
26351 * @cfg {String} href the link
26352 * @cfg {Boolean} disable (true | false) default false
26353 * @cfg {Boolean} preventDefault (true | false) default true
26354 * @cfg {String} icon Font awesome icon
26355 * @cfg {String} pos Submenu align to (left | right) default right
26359 * Create a new Item
26360 * @param {Object} config The config object
26364 Roo.bootstrap.menu.Item = function(config){
26365 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26369 * Fires when the mouse is hovering over this menu
26370 * @param {Roo.bootstrap.menu.Item} this
26371 * @param {Roo.EventObject} e
26376 * Fires when the mouse exits this menu
26377 * @param {Roo.bootstrap.menu.Item} this
26378 * @param {Roo.EventObject} e
26384 * The raw click event for the entire grid.
26385 * @param {Roo.EventObject} e
26391 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26396 preventDefault: true,
26401 getAutoCreate : function()
26406 cls : 'roo-menu-item-text',
26414 cls : 'fa ' + this.icon
26423 href : this.href || '#',
26430 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26434 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26436 if(this.pos == 'left'){
26437 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26444 initEvents : function()
26446 this.el.on('mouseover', this.onMouseOver, this);
26447 this.el.on('mouseout', this.onMouseOut, this);
26449 this.el.select('a', true).first().on('click', this.onClick, this);
26453 onClick : function(e)
26455 if(this.preventDefault){
26456 e.preventDefault();
26459 this.fireEvent("click", this, e);
26462 onMouseOver : function(e)
26464 if(this.submenu && this.pos == 'left'){
26465 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26468 this.fireEvent("mouseover", this, e);
26471 onMouseOut : function(e)
26473 this.fireEvent("mouseout", this, e);
26485 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26488 * @class Roo.bootstrap.menu.Separator
26489 * @extends Roo.bootstrap.Component
26490 * Bootstrap Separator class
26493 * Create a new Separator
26494 * @param {Object} config The config object
26498 Roo.bootstrap.menu.Separator = function(config){
26499 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26502 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26504 getAutoCreate : function(){
26525 * @class Roo.bootstrap.Tooltip
26526 * Bootstrap Tooltip class
26527 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26528 * to determine which dom element triggers the tooltip.
26530 * It needs to add support for additional attributes like tooltip-position
26533 * Create a new Toolti
26534 * @param {Object} config The config object
26537 Roo.bootstrap.Tooltip = function(config){
26538 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26540 this.alignment = Roo.bootstrap.Tooltip.alignment;
26542 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26543 this.alignment = config.alignment;
26548 Roo.apply(Roo.bootstrap.Tooltip, {
26550 * @function init initialize tooltip monitoring.
26554 currentTip : false,
26555 currentRegion : false,
26561 Roo.get(document).on('mouseover', this.enter ,this);
26562 Roo.get(document).on('mouseout', this.leave, this);
26565 this.currentTip = new Roo.bootstrap.Tooltip();
26568 enter : function(ev)
26570 var dom = ev.getTarget();
26572 //Roo.log(['enter',dom]);
26573 var el = Roo.fly(dom);
26574 if (this.currentEl) {
26576 //Roo.log(this.currentEl);
26577 //Roo.log(this.currentEl.contains(dom));
26578 if (this.currentEl == el) {
26581 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26587 if (this.currentTip.el) {
26588 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26592 if(!el || el.dom == document){
26598 // you can not look for children, as if el is the body.. then everythign is the child..
26599 if (!el.attr('tooltip')) { //
26600 if (!el.select("[tooltip]").elements.length) {
26603 // is the mouse over this child...?
26604 bindEl = el.select("[tooltip]").first();
26605 var xy = ev.getXY();
26606 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26607 //Roo.log("not in region.");
26610 //Roo.log("child element over..");
26613 this.currentEl = bindEl;
26614 this.currentTip.bind(bindEl);
26615 this.currentRegion = Roo.lib.Region.getRegion(dom);
26616 this.currentTip.enter();
26619 leave : function(ev)
26621 var dom = ev.getTarget();
26622 //Roo.log(['leave',dom]);
26623 if (!this.currentEl) {
26628 if (dom != this.currentEl.dom) {
26631 var xy = ev.getXY();
26632 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26635 // only activate leave if mouse cursor is outside... bounding box..
26640 if (this.currentTip) {
26641 this.currentTip.leave();
26643 //Roo.log('clear currentEl');
26644 this.currentEl = false;
26649 'left' : ['r-l', [-2,0], 'right'],
26650 'right' : ['l-r', [2,0], 'left'],
26651 'bottom' : ['t-b', [0,2], 'top'],
26652 'top' : [ 'b-t', [0,-2], 'bottom']
26658 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26663 delay : null, // can be { show : 300 , hide: 500}
26667 hoverState : null, //???
26669 placement : 'bottom',
26673 getAutoCreate : function(){
26680 cls : 'tooltip-arrow'
26683 cls : 'tooltip-inner'
26690 bind : function(el)
26696 enter : function () {
26698 if (this.timeout != null) {
26699 clearTimeout(this.timeout);
26702 this.hoverState = 'in';
26703 //Roo.log("enter - show");
26704 if (!this.delay || !this.delay.show) {
26709 this.timeout = setTimeout(function () {
26710 if (_t.hoverState == 'in') {
26713 }, this.delay.show);
26717 clearTimeout(this.timeout);
26719 this.hoverState = 'out';
26720 if (!this.delay || !this.delay.hide) {
26726 this.timeout = setTimeout(function () {
26727 //Roo.log("leave - timeout");
26729 if (_t.hoverState == 'out') {
26731 Roo.bootstrap.Tooltip.currentEl = false;
26736 show : function (msg)
26739 this.render(document.body);
26742 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26744 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26746 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26748 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26750 var placement = typeof this.placement == 'function' ?
26751 this.placement.call(this, this.el, on_el) :
26754 var autoToken = /\s?auto?\s?/i;
26755 var autoPlace = autoToken.test(placement);
26757 placement = placement.replace(autoToken, '') || 'top';
26761 //this.el.setXY([0,0]);
26763 //this.el.dom.style.display='block';
26765 //this.el.appendTo(on_el);
26767 var p = this.getPosition();
26768 var box = this.el.getBox();
26774 var align = this.alignment[placement];
26776 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26778 if(placement == 'top' || placement == 'bottom'){
26780 placement = 'right';
26783 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26784 placement = 'left';
26787 var scroll = Roo.select('body', true).first().getScroll();
26789 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26793 align = this.alignment[placement];
26796 this.el.alignTo(this.bindEl, align[0],align[1]);
26797 //var arrow = this.el.select('.arrow',true).first();
26798 //arrow.set(align[2],
26800 this.el.addClass(placement);
26802 this.el.addClass('in fade');
26804 this.hoverState = null;
26806 if (this.el.hasClass('fade')) {
26817 //this.el.setXY([0,0]);
26818 this.el.removeClass('in');
26834 * @class Roo.bootstrap.LocationPicker
26835 * @extends Roo.bootstrap.Component
26836 * Bootstrap LocationPicker class
26837 * @cfg {Number} latitude Position when init default 0
26838 * @cfg {Number} longitude Position when init default 0
26839 * @cfg {Number} zoom default 15
26840 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26841 * @cfg {Boolean} mapTypeControl default false
26842 * @cfg {Boolean} disableDoubleClickZoom default false
26843 * @cfg {Boolean} scrollwheel default true
26844 * @cfg {Boolean} streetViewControl default false
26845 * @cfg {Number} radius default 0
26846 * @cfg {String} locationName
26847 * @cfg {Boolean} draggable default true
26848 * @cfg {Boolean} enableAutocomplete default false
26849 * @cfg {Boolean} enableReverseGeocode default true
26850 * @cfg {String} markerTitle
26853 * Create a new LocationPicker
26854 * @param {Object} config The config object
26858 Roo.bootstrap.LocationPicker = function(config){
26860 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26865 * Fires when the picker initialized.
26866 * @param {Roo.bootstrap.LocationPicker} this
26867 * @param {Google Location} location
26871 * @event positionchanged
26872 * Fires when the picker position changed.
26873 * @param {Roo.bootstrap.LocationPicker} this
26874 * @param {Google Location} location
26876 positionchanged : true,
26879 * Fires when the map resize.
26880 * @param {Roo.bootstrap.LocationPicker} this
26885 * Fires when the map show.
26886 * @param {Roo.bootstrap.LocationPicker} this
26891 * Fires when the map hide.
26892 * @param {Roo.bootstrap.LocationPicker} this
26897 * Fires when click the map.
26898 * @param {Roo.bootstrap.LocationPicker} this
26899 * @param {Map event} e
26903 * @event mapRightClick
26904 * Fires when right click the map.
26905 * @param {Roo.bootstrap.LocationPicker} this
26906 * @param {Map event} e
26908 mapRightClick : true,
26910 * @event markerClick
26911 * Fires when click the marker.
26912 * @param {Roo.bootstrap.LocationPicker} this
26913 * @param {Map event} e
26915 markerClick : true,
26917 * @event markerRightClick
26918 * Fires when right click the marker.
26919 * @param {Roo.bootstrap.LocationPicker} this
26920 * @param {Map event} e
26922 markerRightClick : true,
26924 * @event OverlayViewDraw
26925 * Fires when OverlayView Draw
26926 * @param {Roo.bootstrap.LocationPicker} this
26928 OverlayViewDraw : true,
26930 * @event OverlayViewOnAdd
26931 * Fires when OverlayView Draw
26932 * @param {Roo.bootstrap.LocationPicker} this
26934 OverlayViewOnAdd : true,
26936 * @event OverlayViewOnRemove
26937 * Fires when OverlayView Draw
26938 * @param {Roo.bootstrap.LocationPicker} this
26940 OverlayViewOnRemove : true,
26942 * @event OverlayViewShow
26943 * Fires when OverlayView Draw
26944 * @param {Roo.bootstrap.LocationPicker} this
26945 * @param {Pixel} cpx
26947 OverlayViewShow : true,
26949 * @event OverlayViewHide
26950 * Fires when OverlayView Draw
26951 * @param {Roo.bootstrap.LocationPicker} this
26953 OverlayViewHide : true,
26955 * @event loadexception
26956 * Fires when load google lib failed.
26957 * @param {Roo.bootstrap.LocationPicker} this
26959 loadexception : true
26964 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26966 gMapContext: false,
26972 mapTypeControl: false,
26973 disableDoubleClickZoom: false,
26975 streetViewControl: false,
26979 enableAutocomplete: false,
26980 enableReverseGeocode: true,
26983 getAutoCreate: function()
26988 cls: 'roo-location-picker'
26994 initEvents: function(ct, position)
26996 if(!this.el.getWidth() || this.isApplied()){
27000 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27005 initial: function()
27007 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
27008 this.fireEvent('loadexception', this);
27012 if(!this.mapTypeId){
27013 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
27016 this.gMapContext = this.GMapContext();
27018 this.initOverlayView();
27020 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
27024 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
27025 _this.setPosition(_this.gMapContext.marker.position);
27028 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
27029 _this.fireEvent('mapClick', this, event);
27033 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
27034 _this.fireEvent('mapRightClick', this, event);
27038 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
27039 _this.fireEvent('markerClick', this, event);
27043 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
27044 _this.fireEvent('markerRightClick', this, event);
27048 this.setPosition(this.gMapContext.location);
27050 this.fireEvent('initial', this, this.gMapContext.location);
27053 initOverlayView: function()
27057 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27061 _this.fireEvent('OverlayViewDraw', _this);
27066 _this.fireEvent('OverlayViewOnAdd', _this);
27069 onRemove: function()
27071 _this.fireEvent('OverlayViewOnRemove', _this);
27074 show: function(cpx)
27076 _this.fireEvent('OverlayViewShow', _this, cpx);
27081 _this.fireEvent('OverlayViewHide', _this);
27087 fromLatLngToContainerPixel: function(event)
27089 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27092 isApplied: function()
27094 return this.getGmapContext() == false ? false : true;
27097 getGmapContext: function()
27099 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27102 GMapContext: function()
27104 var position = new google.maps.LatLng(this.latitude, this.longitude);
27106 var _map = new google.maps.Map(this.el.dom, {
27109 mapTypeId: this.mapTypeId,
27110 mapTypeControl: this.mapTypeControl,
27111 disableDoubleClickZoom: this.disableDoubleClickZoom,
27112 scrollwheel: this.scrollwheel,
27113 streetViewControl: this.streetViewControl,
27114 locationName: this.locationName,
27115 draggable: this.draggable,
27116 enableAutocomplete: this.enableAutocomplete,
27117 enableReverseGeocode: this.enableReverseGeocode
27120 var _marker = new google.maps.Marker({
27121 position: position,
27123 title: this.markerTitle,
27124 draggable: this.draggable
27131 location: position,
27132 radius: this.radius,
27133 locationName: this.locationName,
27134 addressComponents: {
27135 formatted_address: null,
27136 addressLine1: null,
27137 addressLine2: null,
27139 streetNumber: null,
27143 stateOrProvince: null
27146 domContainer: this.el.dom,
27147 geodecoder: new google.maps.Geocoder()
27151 drawCircle: function(center, radius, options)
27153 if (this.gMapContext.circle != null) {
27154 this.gMapContext.circle.setMap(null);
27158 options = Roo.apply({}, options, {
27159 strokeColor: "#0000FF",
27160 strokeOpacity: .35,
27162 fillColor: "#0000FF",
27166 options.map = this.gMapContext.map;
27167 options.radius = radius;
27168 options.center = center;
27169 this.gMapContext.circle = new google.maps.Circle(options);
27170 return this.gMapContext.circle;
27176 setPosition: function(location)
27178 this.gMapContext.location = location;
27179 this.gMapContext.marker.setPosition(location);
27180 this.gMapContext.map.panTo(location);
27181 this.drawCircle(location, this.gMapContext.radius, {});
27185 if (this.gMapContext.settings.enableReverseGeocode) {
27186 this.gMapContext.geodecoder.geocode({
27187 latLng: this.gMapContext.location
27188 }, function(results, status) {
27190 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27191 _this.gMapContext.locationName = results[0].formatted_address;
27192 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27194 _this.fireEvent('positionchanged', this, location);
27201 this.fireEvent('positionchanged', this, location);
27206 google.maps.event.trigger(this.gMapContext.map, "resize");
27208 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27210 this.fireEvent('resize', this);
27213 setPositionByLatLng: function(latitude, longitude)
27215 this.setPosition(new google.maps.LatLng(latitude, longitude));
27218 getCurrentPosition: function()
27221 latitude: this.gMapContext.location.lat(),
27222 longitude: this.gMapContext.location.lng()
27226 getAddressName: function()
27228 return this.gMapContext.locationName;
27231 getAddressComponents: function()
27233 return this.gMapContext.addressComponents;
27236 address_component_from_google_geocode: function(address_components)
27240 for (var i = 0; i < address_components.length; i++) {
27241 var component = address_components[i];
27242 if (component.types.indexOf("postal_code") >= 0) {
27243 result.postalCode = component.short_name;
27244 } else if (component.types.indexOf("street_number") >= 0) {
27245 result.streetNumber = component.short_name;
27246 } else if (component.types.indexOf("route") >= 0) {
27247 result.streetName = component.short_name;
27248 } else if (component.types.indexOf("neighborhood") >= 0) {
27249 result.city = component.short_name;
27250 } else if (component.types.indexOf("locality") >= 0) {
27251 result.city = component.short_name;
27252 } else if (component.types.indexOf("sublocality") >= 0) {
27253 result.district = component.short_name;
27254 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27255 result.stateOrProvince = component.short_name;
27256 } else if (component.types.indexOf("country") >= 0) {
27257 result.country = component.short_name;
27261 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27262 result.addressLine2 = "";
27266 setZoomLevel: function(zoom)
27268 this.gMapContext.map.setZoom(zoom);
27281 this.fireEvent('show', this);
27292 this.fireEvent('hide', this);
27297 Roo.apply(Roo.bootstrap.LocationPicker, {
27299 OverlayView : function(map, options)
27301 options = options || {};
27308 * @class Roo.bootstrap.Alert
27309 * @extends Roo.bootstrap.Component
27310 * Bootstrap Alert class - shows an alert area box
27312 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27313 Enter a valid email address
27316 * @cfg {String} title The title of alert
27317 * @cfg {String} html The content of alert
27318 * @cfg {String} weight ( success | info | warning | danger )
27319 * @cfg {String} faicon font-awesomeicon
27322 * Create a new alert
27323 * @param {Object} config The config object
27327 Roo.bootstrap.Alert = function(config){
27328 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27332 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27339 getAutoCreate : function()
27348 cls : 'roo-alert-icon'
27353 cls : 'roo-alert-title',
27358 cls : 'roo-alert-text',
27365 cfg.cn[0].cls += ' fa ' + this.faicon;
27369 cfg.cls += ' alert-' + this.weight;
27375 initEvents: function()
27377 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27380 setTitle : function(str)
27382 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27385 setText : function(str)
27387 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27390 setWeight : function(weight)
27393 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27396 this.weight = weight;
27398 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27401 setIcon : function(icon)
27404 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27407 this.faicon = icon;
27409 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27430 * @class Roo.bootstrap.UploadCropbox
27431 * @extends Roo.bootstrap.Component
27432 * Bootstrap UploadCropbox class
27433 * @cfg {String} emptyText show when image has been loaded
27434 * @cfg {String} rotateNotify show when image too small to rotate
27435 * @cfg {Number} errorTimeout default 3000
27436 * @cfg {Number} minWidth default 300
27437 * @cfg {Number} minHeight default 300
27438 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27439 * @cfg {Boolean} isDocument (true|false) default false
27440 * @cfg {String} url action url
27441 * @cfg {String} paramName default 'imageUpload'
27442 * @cfg {String} method default POST
27443 * @cfg {Boolean} loadMask (true|false) default true
27444 * @cfg {Boolean} loadingText default 'Loading...'
27447 * Create a new UploadCropbox
27448 * @param {Object} config The config object
27451 Roo.bootstrap.UploadCropbox = function(config){
27452 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27456 * @event beforeselectfile
27457 * Fire before select file
27458 * @param {Roo.bootstrap.UploadCropbox} this
27460 "beforeselectfile" : true,
27463 * Fire after initEvent
27464 * @param {Roo.bootstrap.UploadCropbox} this
27469 * Fire after initEvent
27470 * @param {Roo.bootstrap.UploadCropbox} this
27471 * @param {String} data
27476 * Fire when preparing the file data
27477 * @param {Roo.bootstrap.UploadCropbox} this
27478 * @param {Object} file
27483 * Fire when get exception
27484 * @param {Roo.bootstrap.UploadCropbox} this
27485 * @param {XMLHttpRequest} xhr
27487 "exception" : true,
27489 * @event beforeloadcanvas
27490 * Fire before load the canvas
27491 * @param {Roo.bootstrap.UploadCropbox} this
27492 * @param {String} src
27494 "beforeloadcanvas" : true,
27497 * Fire when trash image
27498 * @param {Roo.bootstrap.UploadCropbox} this
27503 * Fire when download the image
27504 * @param {Roo.bootstrap.UploadCropbox} this
27508 * @event footerbuttonclick
27509 * Fire when footerbuttonclick
27510 * @param {Roo.bootstrap.UploadCropbox} this
27511 * @param {String} type
27513 "footerbuttonclick" : true,
27517 * @param {Roo.bootstrap.UploadCropbox} this
27522 * Fire when rotate the image
27523 * @param {Roo.bootstrap.UploadCropbox} this
27524 * @param {String} pos
27529 * Fire when inspect the file
27530 * @param {Roo.bootstrap.UploadCropbox} this
27531 * @param {Object} file
27536 * Fire when xhr upload the file
27537 * @param {Roo.bootstrap.UploadCropbox} this
27538 * @param {Object} data
27543 * Fire when arrange the file data
27544 * @param {Roo.bootstrap.UploadCropbox} this
27545 * @param {Object} formData
27550 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27553 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27555 emptyText : 'Click to upload image',
27556 rotateNotify : 'Image is too small to rotate',
27557 errorTimeout : 3000,
27571 cropType : 'image/jpeg',
27573 canvasLoaded : false,
27574 isDocument : false,
27576 paramName : 'imageUpload',
27578 loadingText : 'Loading...',
27581 getAutoCreate : function()
27585 cls : 'roo-upload-cropbox',
27589 cls : 'roo-upload-cropbox-selector',
27594 cls : 'roo-upload-cropbox-body',
27595 style : 'cursor:pointer',
27599 cls : 'roo-upload-cropbox-preview'
27603 cls : 'roo-upload-cropbox-thumb'
27607 cls : 'roo-upload-cropbox-empty-notify',
27608 html : this.emptyText
27612 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27613 html : this.rotateNotify
27619 cls : 'roo-upload-cropbox-footer',
27622 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27632 onRender : function(ct, position)
27634 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27636 if (this.buttons.length) {
27638 Roo.each(this.buttons, function(bb) {
27640 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27642 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27648 this.maskEl = this.el;
27652 initEvents : function()
27654 this.urlAPI = (window.createObjectURL && window) ||
27655 (window.URL && URL.revokeObjectURL && URL) ||
27656 (window.webkitURL && webkitURL);
27658 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27659 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27661 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27662 this.selectorEl.hide();
27664 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27665 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27667 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27668 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27669 this.thumbEl.hide();
27671 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27672 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27674 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27675 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27676 this.errorEl.hide();
27678 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27679 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27680 this.footerEl.hide();
27682 this.setThumbBoxSize();
27688 this.fireEvent('initial', this);
27695 window.addEventListener("resize", function() { _this.resize(); } );
27697 this.bodyEl.on('click', this.beforeSelectFile, this);
27700 this.bodyEl.on('touchstart', this.onTouchStart, this);
27701 this.bodyEl.on('touchmove', this.onTouchMove, this);
27702 this.bodyEl.on('touchend', this.onTouchEnd, this);
27706 this.bodyEl.on('mousedown', this.onMouseDown, this);
27707 this.bodyEl.on('mousemove', this.onMouseMove, this);
27708 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27709 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27710 Roo.get(document).on('mouseup', this.onMouseUp, this);
27713 this.selectorEl.on('change', this.onFileSelected, this);
27719 this.baseScale = 1;
27721 this.baseRotate = 1;
27722 this.dragable = false;
27723 this.pinching = false;
27726 this.cropData = false;
27727 this.notifyEl.dom.innerHTML = this.emptyText;
27729 this.selectorEl.dom.value = '';
27733 resize : function()
27735 if(this.fireEvent('resize', this) != false){
27736 this.setThumbBoxPosition();
27737 this.setCanvasPosition();
27741 onFooterButtonClick : function(e, el, o, type)
27744 case 'rotate-left' :
27745 this.onRotateLeft(e);
27747 case 'rotate-right' :
27748 this.onRotateRight(e);
27751 this.beforeSelectFile(e);
27766 this.fireEvent('footerbuttonclick', this, type);
27769 beforeSelectFile : function(e)
27771 e.preventDefault();
27773 if(this.fireEvent('beforeselectfile', this) != false){
27774 this.selectorEl.dom.click();
27778 onFileSelected : function(e)
27780 e.preventDefault();
27782 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27786 var file = this.selectorEl.dom.files[0];
27788 if(this.fireEvent('inspect', this, file) != false){
27789 this.prepare(file);
27794 trash : function(e)
27796 this.fireEvent('trash', this);
27799 download : function(e)
27801 this.fireEvent('download', this);
27804 loadCanvas : function(src)
27806 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27810 this.imageEl = document.createElement('img');
27814 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27816 this.imageEl.src = src;
27820 onLoadCanvas : function()
27822 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27823 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27825 this.bodyEl.un('click', this.beforeSelectFile, this);
27827 this.notifyEl.hide();
27828 this.thumbEl.show();
27829 this.footerEl.show();
27831 this.baseRotateLevel();
27833 if(this.isDocument){
27834 this.setThumbBoxSize();
27837 this.setThumbBoxPosition();
27839 this.baseScaleLevel();
27845 this.canvasLoaded = true;
27848 this.maskEl.unmask();
27853 setCanvasPosition : function()
27855 if(!this.canvasEl){
27859 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27860 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27862 this.previewEl.setLeft(pw);
27863 this.previewEl.setTop(ph);
27867 onMouseDown : function(e)
27871 this.dragable = true;
27872 this.pinching = false;
27874 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27875 this.dragable = false;
27879 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27880 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27884 onMouseMove : function(e)
27888 if(!this.canvasLoaded){
27892 if (!this.dragable){
27896 var minX = Math.ceil(this.thumbEl.getLeft(true));
27897 var minY = Math.ceil(this.thumbEl.getTop(true));
27899 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27900 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27902 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27903 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27905 x = x - this.mouseX;
27906 y = y - this.mouseY;
27908 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27909 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27911 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27912 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27914 this.previewEl.setLeft(bgX);
27915 this.previewEl.setTop(bgY);
27917 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27918 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27921 onMouseUp : function(e)
27925 this.dragable = false;
27928 onMouseWheel : function(e)
27932 this.startScale = this.scale;
27934 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27936 if(!this.zoomable()){
27937 this.scale = this.startScale;
27946 zoomable : function()
27948 var minScale = this.thumbEl.getWidth() / this.minWidth;
27950 if(this.minWidth < this.minHeight){
27951 minScale = this.thumbEl.getHeight() / this.minHeight;
27954 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27955 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27959 (this.rotate == 0 || this.rotate == 180) &&
27961 width > this.imageEl.OriginWidth ||
27962 height > this.imageEl.OriginHeight ||
27963 (width < this.minWidth && height < this.minHeight)
27971 (this.rotate == 90 || this.rotate == 270) &&
27973 width > this.imageEl.OriginWidth ||
27974 height > this.imageEl.OriginHeight ||
27975 (width < this.minHeight && height < this.minWidth)
27982 !this.isDocument &&
27983 (this.rotate == 0 || this.rotate == 180) &&
27985 width < this.minWidth ||
27986 width > this.imageEl.OriginWidth ||
27987 height < this.minHeight ||
27988 height > this.imageEl.OriginHeight
27995 !this.isDocument &&
27996 (this.rotate == 90 || this.rotate == 270) &&
27998 width < this.minHeight ||
27999 width > this.imageEl.OriginWidth ||
28000 height < this.minWidth ||
28001 height > this.imageEl.OriginHeight
28011 onRotateLeft : function(e)
28013 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28015 var minScale = this.thumbEl.getWidth() / this.minWidth;
28017 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28018 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28020 this.startScale = this.scale;
28022 while (this.getScaleLevel() < minScale){
28024 this.scale = this.scale + 1;
28026 if(!this.zoomable()){
28031 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28032 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28037 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28044 this.scale = this.startScale;
28046 this.onRotateFail();
28051 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28053 if(this.isDocument){
28054 this.setThumbBoxSize();
28055 this.setThumbBoxPosition();
28056 this.setCanvasPosition();
28061 this.fireEvent('rotate', this, 'left');
28065 onRotateRight : function(e)
28067 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28069 var minScale = this.thumbEl.getWidth() / this.minWidth;
28071 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28072 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28074 this.startScale = this.scale;
28076 while (this.getScaleLevel() < minScale){
28078 this.scale = this.scale + 1;
28080 if(!this.zoomable()){
28085 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28086 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28091 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28098 this.scale = this.startScale;
28100 this.onRotateFail();
28105 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28107 if(this.isDocument){
28108 this.setThumbBoxSize();
28109 this.setThumbBoxPosition();
28110 this.setCanvasPosition();
28115 this.fireEvent('rotate', this, 'right');
28118 onRotateFail : function()
28120 this.errorEl.show(true);
28124 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28129 this.previewEl.dom.innerHTML = '';
28131 var canvasEl = document.createElement("canvas");
28133 var contextEl = canvasEl.getContext("2d");
28135 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28136 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28137 var center = this.imageEl.OriginWidth / 2;
28139 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28140 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28141 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28142 center = this.imageEl.OriginHeight / 2;
28145 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28147 contextEl.translate(center, center);
28148 contextEl.rotate(this.rotate * Math.PI / 180);
28150 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28152 this.canvasEl = document.createElement("canvas");
28154 this.contextEl = this.canvasEl.getContext("2d");
28156 switch (this.rotate) {
28159 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28160 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28162 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28167 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28168 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28170 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28171 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);
28175 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28180 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28181 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28183 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28184 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);
28188 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);
28193 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28194 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28196 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28197 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28201 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);
28208 this.previewEl.appendChild(this.canvasEl);
28210 this.setCanvasPosition();
28215 if(!this.canvasLoaded){
28219 var imageCanvas = document.createElement("canvas");
28221 var imageContext = imageCanvas.getContext("2d");
28223 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28224 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28226 var center = imageCanvas.width / 2;
28228 imageContext.translate(center, center);
28230 imageContext.rotate(this.rotate * Math.PI / 180);
28232 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28234 var canvas = document.createElement("canvas");
28236 var context = canvas.getContext("2d");
28238 canvas.width = this.minWidth;
28239 canvas.height = this.minHeight;
28241 switch (this.rotate) {
28244 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28245 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28247 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28248 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28250 var targetWidth = this.minWidth - 2 * x;
28251 var targetHeight = this.minHeight - 2 * y;
28255 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28256 scale = targetWidth / width;
28259 if(x > 0 && y == 0){
28260 scale = targetHeight / height;
28263 if(x > 0 && y > 0){
28264 scale = targetWidth / width;
28266 if(width < height){
28267 scale = targetHeight / height;
28271 context.scale(scale, scale);
28273 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28274 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28276 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28277 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28279 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28284 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28285 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28287 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28288 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28290 var targetWidth = this.minWidth - 2 * x;
28291 var targetHeight = this.minHeight - 2 * y;
28295 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28296 scale = targetWidth / width;
28299 if(x > 0 && y == 0){
28300 scale = targetHeight / height;
28303 if(x > 0 && y > 0){
28304 scale = targetWidth / width;
28306 if(width < height){
28307 scale = targetHeight / height;
28311 context.scale(scale, scale);
28313 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28314 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28316 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28317 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28319 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28321 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28326 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28327 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28329 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28330 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28332 var targetWidth = this.minWidth - 2 * x;
28333 var targetHeight = this.minHeight - 2 * y;
28337 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28338 scale = targetWidth / width;
28341 if(x > 0 && y == 0){
28342 scale = targetHeight / height;
28345 if(x > 0 && y > 0){
28346 scale = targetWidth / width;
28348 if(width < height){
28349 scale = targetHeight / height;
28353 context.scale(scale, scale);
28355 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28356 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28358 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28359 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28361 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28362 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28364 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28369 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28370 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28372 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28373 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28375 var targetWidth = this.minWidth - 2 * x;
28376 var targetHeight = this.minHeight - 2 * y;
28380 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28381 scale = targetWidth / width;
28384 if(x > 0 && y == 0){
28385 scale = targetHeight / height;
28388 if(x > 0 && y > 0){
28389 scale = targetWidth / width;
28391 if(width < height){
28392 scale = targetHeight / height;
28396 context.scale(scale, scale);
28398 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28399 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28401 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28402 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28404 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28406 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28413 this.cropData = canvas.toDataURL(this.cropType);
28415 if(this.fireEvent('crop', this, this.cropData) !== false){
28416 this.process(this.file, this.cropData);
28423 setThumbBoxSize : function()
28427 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28428 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28429 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28431 this.minWidth = width;
28432 this.minHeight = height;
28434 if(this.rotate == 90 || this.rotate == 270){
28435 this.minWidth = height;
28436 this.minHeight = width;
28441 width = Math.ceil(this.minWidth * height / this.minHeight);
28443 if(this.minWidth > this.minHeight){
28445 height = Math.ceil(this.minHeight * width / this.minWidth);
28448 this.thumbEl.setStyle({
28449 width : width + 'px',
28450 height : height + 'px'
28457 setThumbBoxPosition : function()
28459 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28460 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28462 this.thumbEl.setLeft(x);
28463 this.thumbEl.setTop(y);
28467 baseRotateLevel : function()
28469 this.baseRotate = 1;
28472 typeof(this.exif) != 'undefined' &&
28473 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28474 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28476 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28479 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28483 baseScaleLevel : function()
28487 if(this.isDocument){
28489 if(this.baseRotate == 6 || this.baseRotate == 8){
28491 height = this.thumbEl.getHeight();
28492 this.baseScale = height / this.imageEl.OriginWidth;
28494 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28495 width = this.thumbEl.getWidth();
28496 this.baseScale = width / this.imageEl.OriginHeight;
28502 height = this.thumbEl.getHeight();
28503 this.baseScale = height / this.imageEl.OriginHeight;
28505 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28506 width = this.thumbEl.getWidth();
28507 this.baseScale = width / this.imageEl.OriginWidth;
28513 if(this.baseRotate == 6 || this.baseRotate == 8){
28515 width = this.thumbEl.getHeight();
28516 this.baseScale = width / this.imageEl.OriginHeight;
28518 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28519 height = this.thumbEl.getWidth();
28520 this.baseScale = height / this.imageEl.OriginHeight;
28523 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28524 height = this.thumbEl.getWidth();
28525 this.baseScale = height / this.imageEl.OriginHeight;
28527 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28528 width = this.thumbEl.getHeight();
28529 this.baseScale = width / this.imageEl.OriginWidth;
28536 width = this.thumbEl.getWidth();
28537 this.baseScale = width / this.imageEl.OriginWidth;
28539 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28540 height = this.thumbEl.getHeight();
28541 this.baseScale = height / this.imageEl.OriginHeight;
28544 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28546 height = this.thumbEl.getHeight();
28547 this.baseScale = height / this.imageEl.OriginHeight;
28549 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28550 width = this.thumbEl.getWidth();
28551 this.baseScale = width / this.imageEl.OriginWidth;
28559 getScaleLevel : function()
28561 return this.baseScale * Math.pow(1.1, this.scale);
28564 onTouchStart : function(e)
28566 if(!this.canvasLoaded){
28567 this.beforeSelectFile(e);
28571 var touches = e.browserEvent.touches;
28577 if(touches.length == 1){
28578 this.onMouseDown(e);
28582 if(touches.length != 2){
28588 for(var i = 0, finger; finger = touches[i]; i++){
28589 coords.push(finger.pageX, finger.pageY);
28592 var x = Math.pow(coords[0] - coords[2], 2);
28593 var y = Math.pow(coords[1] - coords[3], 2);
28595 this.startDistance = Math.sqrt(x + y);
28597 this.startScale = this.scale;
28599 this.pinching = true;
28600 this.dragable = false;
28604 onTouchMove : function(e)
28606 if(!this.pinching && !this.dragable){
28610 var touches = e.browserEvent.touches;
28617 this.onMouseMove(e);
28623 for(var i = 0, finger; finger = touches[i]; i++){
28624 coords.push(finger.pageX, finger.pageY);
28627 var x = Math.pow(coords[0] - coords[2], 2);
28628 var y = Math.pow(coords[1] - coords[3], 2);
28630 this.endDistance = Math.sqrt(x + y);
28632 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28634 if(!this.zoomable()){
28635 this.scale = this.startScale;
28643 onTouchEnd : function(e)
28645 this.pinching = false;
28646 this.dragable = false;
28650 process : function(file, crop)
28653 this.maskEl.mask(this.loadingText);
28656 this.xhr = new XMLHttpRequest();
28658 file.xhr = this.xhr;
28660 this.xhr.open(this.method, this.url, true);
28663 "Accept": "application/json",
28664 "Cache-Control": "no-cache",
28665 "X-Requested-With": "XMLHttpRequest"
28668 for (var headerName in headers) {
28669 var headerValue = headers[headerName];
28671 this.xhr.setRequestHeader(headerName, headerValue);
28677 this.xhr.onload = function()
28679 _this.xhrOnLoad(_this.xhr);
28682 this.xhr.onerror = function()
28684 _this.xhrOnError(_this.xhr);
28687 var formData = new FormData();
28689 formData.append('returnHTML', 'NO');
28692 formData.append('crop', crop);
28695 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28696 formData.append(this.paramName, file, file.name);
28699 if(typeof(file.filename) != 'undefined'){
28700 formData.append('filename', file.filename);
28703 if(typeof(file.mimetype) != 'undefined'){
28704 formData.append('mimetype', file.mimetype);
28707 if(this.fireEvent('arrange', this, formData) != false){
28708 this.xhr.send(formData);
28712 xhrOnLoad : function(xhr)
28715 this.maskEl.unmask();
28718 if (xhr.readyState !== 4) {
28719 this.fireEvent('exception', this, xhr);
28723 var response = Roo.decode(xhr.responseText);
28725 if(!response.success){
28726 this.fireEvent('exception', this, xhr);
28730 var response = Roo.decode(xhr.responseText);
28732 this.fireEvent('upload', this, response);
28736 xhrOnError : function()
28739 this.maskEl.unmask();
28742 Roo.log('xhr on error');
28744 var response = Roo.decode(xhr.responseText);
28750 prepare : function(file)
28753 this.maskEl.mask(this.loadingText);
28759 if(typeof(file) === 'string'){
28760 this.loadCanvas(file);
28764 if(!file || !this.urlAPI){
28769 this.cropType = file.type;
28773 if(this.fireEvent('prepare', this, this.file) != false){
28775 var reader = new FileReader();
28777 reader.onload = function (e) {
28778 if (e.target.error) {
28779 Roo.log(e.target.error);
28783 var buffer = e.target.result,
28784 dataView = new DataView(buffer),
28786 maxOffset = dataView.byteLength - 4,
28790 if (dataView.getUint16(0) === 0xffd8) {
28791 while (offset < maxOffset) {
28792 markerBytes = dataView.getUint16(offset);
28794 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28795 markerLength = dataView.getUint16(offset + 2) + 2;
28796 if (offset + markerLength > dataView.byteLength) {
28797 Roo.log('Invalid meta data: Invalid segment size.');
28801 if(markerBytes == 0xffe1){
28802 _this.parseExifData(
28809 offset += markerLength;
28819 var url = _this.urlAPI.createObjectURL(_this.file);
28821 _this.loadCanvas(url);
28826 reader.readAsArrayBuffer(this.file);
28832 parseExifData : function(dataView, offset, length)
28834 var tiffOffset = offset + 10,
28838 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28839 // No Exif data, might be XMP data instead
28843 // Check for the ASCII code for "Exif" (0x45786966):
28844 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28845 // No Exif data, might be XMP data instead
28848 if (tiffOffset + 8 > dataView.byteLength) {
28849 Roo.log('Invalid Exif data: Invalid segment size.');
28852 // Check for the two null bytes:
28853 if (dataView.getUint16(offset + 8) !== 0x0000) {
28854 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28857 // Check the byte alignment:
28858 switch (dataView.getUint16(tiffOffset)) {
28860 littleEndian = true;
28863 littleEndian = false;
28866 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28869 // Check for the TIFF tag marker (0x002A):
28870 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28871 Roo.log('Invalid Exif data: Missing TIFF marker.');
28874 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28875 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28877 this.parseExifTags(
28880 tiffOffset + dirOffset,
28885 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28890 if (dirOffset + 6 > dataView.byteLength) {
28891 Roo.log('Invalid Exif data: Invalid directory offset.');
28894 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28895 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28896 if (dirEndOffset + 4 > dataView.byteLength) {
28897 Roo.log('Invalid Exif data: Invalid directory size.');
28900 for (i = 0; i < tagsNumber; i += 1) {
28904 dirOffset + 2 + 12 * i, // tag offset
28908 // Return the offset to the next directory:
28909 return dataView.getUint32(dirEndOffset, littleEndian);
28912 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28914 var tag = dataView.getUint16(offset, littleEndian);
28916 this.exif[tag] = this.getExifValue(
28920 dataView.getUint16(offset + 2, littleEndian), // tag type
28921 dataView.getUint32(offset + 4, littleEndian), // tag length
28926 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28928 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28937 Roo.log('Invalid Exif data: Invalid tag type.');
28941 tagSize = tagType.size * length;
28942 // Determine if the value is contained in the dataOffset bytes,
28943 // or if the value at the dataOffset is a pointer to the actual data:
28944 dataOffset = tagSize > 4 ?
28945 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28946 if (dataOffset + tagSize > dataView.byteLength) {
28947 Roo.log('Invalid Exif data: Invalid data offset.');
28950 if (length === 1) {
28951 return tagType.getValue(dataView, dataOffset, littleEndian);
28954 for (i = 0; i < length; i += 1) {
28955 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28958 if (tagType.ascii) {
28960 // Concatenate the chars:
28961 for (i = 0; i < values.length; i += 1) {
28963 // Ignore the terminating NULL byte(s):
28964 if (c === '\u0000') {
28976 Roo.apply(Roo.bootstrap.UploadCropbox, {
28978 'Orientation': 0x0112
28982 1: 0, //'top-left',
28984 3: 180, //'bottom-right',
28985 // 4: 'bottom-left',
28987 6: 90, //'right-top',
28988 // 7: 'right-bottom',
28989 8: 270 //'left-bottom'
28993 // byte, 8-bit unsigned int:
28995 getValue: function (dataView, dataOffset) {
28996 return dataView.getUint8(dataOffset);
29000 // ascii, 8-bit byte:
29002 getValue: function (dataView, dataOffset) {
29003 return String.fromCharCode(dataView.getUint8(dataOffset));
29008 // short, 16 bit int:
29010 getValue: function (dataView, dataOffset, littleEndian) {
29011 return dataView.getUint16(dataOffset, littleEndian);
29015 // long, 32 bit int:
29017 getValue: function (dataView, dataOffset, littleEndian) {
29018 return dataView.getUint32(dataOffset, littleEndian);
29022 // rational = two long values, first is numerator, second is denominator:
29024 getValue: function (dataView, dataOffset, littleEndian) {
29025 return dataView.getUint32(dataOffset, littleEndian) /
29026 dataView.getUint32(dataOffset + 4, littleEndian);
29030 // slong, 32 bit signed int:
29032 getValue: function (dataView, dataOffset, littleEndian) {
29033 return dataView.getInt32(dataOffset, littleEndian);
29037 // srational, two slongs, first is numerator, second is denominator:
29039 getValue: function (dataView, dataOffset, littleEndian) {
29040 return dataView.getInt32(dataOffset, littleEndian) /
29041 dataView.getInt32(dataOffset + 4, littleEndian);
29051 cls : 'btn-group roo-upload-cropbox-rotate-left',
29052 action : 'rotate-left',
29056 cls : 'btn btn-default',
29057 html : '<i class="fa fa-undo"></i>'
29063 cls : 'btn-group roo-upload-cropbox-picture',
29064 action : 'picture',
29068 cls : 'btn btn-default',
29069 html : '<i class="fa fa-picture-o"></i>'
29075 cls : 'btn-group roo-upload-cropbox-rotate-right',
29076 action : 'rotate-right',
29080 cls : 'btn btn-default',
29081 html : '<i class="fa fa-repeat"></i>'
29089 cls : 'btn-group roo-upload-cropbox-rotate-left',
29090 action : 'rotate-left',
29094 cls : 'btn btn-default',
29095 html : '<i class="fa fa-undo"></i>'
29101 cls : 'btn-group roo-upload-cropbox-download',
29102 action : 'download',
29106 cls : 'btn btn-default',
29107 html : '<i class="fa fa-download"></i>'
29113 cls : 'btn-group roo-upload-cropbox-crop',
29118 cls : 'btn btn-default',
29119 html : '<i class="fa fa-crop"></i>'
29125 cls : 'btn-group roo-upload-cropbox-trash',
29130 cls : 'btn btn-default',
29131 html : '<i class="fa fa-trash"></i>'
29137 cls : 'btn-group roo-upload-cropbox-rotate-right',
29138 action : 'rotate-right',
29142 cls : 'btn btn-default',
29143 html : '<i class="fa fa-repeat"></i>'
29151 cls : 'btn-group roo-upload-cropbox-rotate-left',
29152 action : 'rotate-left',
29156 cls : 'btn btn-default',
29157 html : '<i class="fa fa-undo"></i>'
29163 cls : 'btn-group roo-upload-cropbox-rotate-right',
29164 action : 'rotate-right',
29168 cls : 'btn btn-default',
29169 html : '<i class="fa fa-repeat"></i>'
29182 * @class Roo.bootstrap.DocumentManager
29183 * @extends Roo.bootstrap.Component
29184 * Bootstrap DocumentManager class
29185 * @cfg {String} paramName default 'imageUpload'
29186 * @cfg {String} toolTipName default 'filename'
29187 * @cfg {String} method default POST
29188 * @cfg {String} url action url
29189 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29190 * @cfg {Boolean} multiple multiple upload default true
29191 * @cfg {Number} thumbSize default 300
29192 * @cfg {String} fieldLabel
29193 * @cfg {Number} labelWidth default 4
29194 * @cfg {String} labelAlign (left|top) default left
29195 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29196 * @cfg {Number} labellg set the width of label (1-12)
29197 * @cfg {Number} labelmd set the width of label (1-12)
29198 * @cfg {Number} labelsm set the width of label (1-12)
29199 * @cfg {Number} labelxs set the width of label (1-12)
29202 * Create a new DocumentManager
29203 * @param {Object} config The config object
29206 Roo.bootstrap.DocumentManager = function(config){
29207 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29210 this.delegates = [];
29215 * Fire when initial the DocumentManager
29216 * @param {Roo.bootstrap.DocumentManager} this
29221 * inspect selected file
29222 * @param {Roo.bootstrap.DocumentManager} this
29223 * @param {File} file
29228 * Fire when xhr load exception
29229 * @param {Roo.bootstrap.DocumentManager} this
29230 * @param {XMLHttpRequest} xhr
29232 "exception" : true,
29234 * @event afterupload
29235 * Fire when xhr load exception
29236 * @param {Roo.bootstrap.DocumentManager} this
29237 * @param {XMLHttpRequest} xhr
29239 "afterupload" : true,
29242 * prepare the form data
29243 * @param {Roo.bootstrap.DocumentManager} this
29244 * @param {Object} formData
29249 * Fire when remove the file
29250 * @param {Roo.bootstrap.DocumentManager} this
29251 * @param {Object} file
29256 * Fire after refresh the file
29257 * @param {Roo.bootstrap.DocumentManager} this
29262 * Fire after click the image
29263 * @param {Roo.bootstrap.DocumentManager} this
29264 * @param {Object} file
29269 * Fire when upload a image and editable set to true
29270 * @param {Roo.bootstrap.DocumentManager} this
29271 * @param {Object} file
29275 * @event beforeselectfile
29276 * Fire before select file
29277 * @param {Roo.bootstrap.DocumentManager} this
29279 "beforeselectfile" : true,
29282 * Fire before process file
29283 * @param {Roo.bootstrap.DocumentManager} this
29284 * @param {Object} file
29288 * @event previewrendered
29289 * Fire when preview rendered
29290 * @param {Roo.bootstrap.DocumentManager} this
29291 * @param {Object} file
29293 "previewrendered" : true,
29296 "previewResize" : true
29301 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29310 paramName : 'imageUpload',
29311 toolTipName : 'filename',
29314 labelAlign : 'left',
29324 getAutoCreate : function()
29326 var managerWidget = {
29328 cls : 'roo-document-manager',
29332 cls : 'roo-document-manager-selector',
29337 cls : 'roo-document-manager-uploader',
29341 cls : 'roo-document-manager-upload-btn',
29342 html : '<i class="fa fa-plus"></i>'
29353 cls : 'column col-md-12',
29358 if(this.fieldLabel.length){
29363 cls : 'column col-md-12',
29364 html : this.fieldLabel
29368 cls : 'column col-md-12',
29373 if(this.labelAlign == 'left'){
29378 html : this.fieldLabel
29387 if(this.labelWidth > 12){
29388 content[0].style = "width: " + this.labelWidth + 'px';
29391 if(this.labelWidth < 13 && this.labelmd == 0){
29392 this.labelmd = this.labelWidth;
29395 if(this.labellg > 0){
29396 content[0].cls += ' col-lg-' + this.labellg;
29397 content[1].cls += ' col-lg-' + (12 - this.labellg);
29400 if(this.labelmd > 0){
29401 content[0].cls += ' col-md-' + this.labelmd;
29402 content[1].cls += ' col-md-' + (12 - this.labelmd);
29405 if(this.labelsm > 0){
29406 content[0].cls += ' col-sm-' + this.labelsm;
29407 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29410 if(this.labelxs > 0){
29411 content[0].cls += ' col-xs-' + this.labelxs;
29412 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29420 cls : 'row clearfix',
29428 initEvents : function()
29430 this.managerEl = this.el.select('.roo-document-manager', true).first();
29431 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29433 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29434 this.selectorEl.hide();
29437 this.selectorEl.attr('multiple', 'multiple');
29440 this.selectorEl.on('change', this.onFileSelected, this);
29442 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29443 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29445 this.uploader.on('click', this.onUploaderClick, this);
29447 this.renderProgressDialog();
29451 window.addEventListener("resize", function() { _this.refresh(); } );
29453 this.fireEvent('initial', this);
29456 renderProgressDialog : function()
29460 this.progressDialog = new Roo.bootstrap.Modal({
29461 cls : 'roo-document-manager-progress-dialog',
29462 allow_close : false,
29473 btnclick : function() {
29474 _this.uploadCancel();
29480 this.progressDialog.render(Roo.get(document.body));
29482 this.progress = new Roo.bootstrap.Progress({
29483 cls : 'roo-document-manager-progress',
29488 this.progress.render(this.progressDialog.getChildContainer());
29490 this.progressBar = new Roo.bootstrap.ProgressBar({
29491 cls : 'roo-document-manager-progress-bar',
29494 aria_valuemax : 12,
29498 this.progressBar.render(this.progress.getChildContainer());
29501 onUploaderClick : function(e)
29503 e.preventDefault();
29505 if(this.fireEvent('beforeselectfile', this) != false){
29506 this.selectorEl.dom.click();
29511 onFileSelected : function(e)
29513 e.preventDefault();
29515 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29519 Roo.each(this.selectorEl.dom.files, function(file){
29520 if(this.fireEvent('inspect', this, file) != false){
29521 this.files.push(file);
29531 this.selectorEl.dom.value = '';
29533 if(!this.files || !this.files.length){
29537 if(this.boxes > 0 && this.files.length > this.boxes){
29538 this.files = this.files.slice(0, this.boxes);
29541 this.uploader.show();
29543 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29544 this.uploader.hide();
29553 Roo.each(this.files, function(file){
29555 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29556 var f = this.renderPreview(file);
29561 if(file.type.indexOf('image') != -1){
29562 this.delegates.push(
29564 _this.process(file);
29565 }).createDelegate(this)
29573 _this.process(file);
29574 }).createDelegate(this)
29579 this.files = files;
29581 this.delegates = this.delegates.concat(docs);
29583 if(!this.delegates.length){
29588 this.progressBar.aria_valuemax = this.delegates.length;
29595 arrange : function()
29597 if(!this.delegates.length){
29598 this.progressDialog.hide();
29603 var delegate = this.delegates.shift();
29605 this.progressDialog.show();
29607 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29609 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29614 refresh : function()
29616 this.uploader.show();
29618 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29619 this.uploader.hide();
29622 Roo.isTouch ? this.closable(false) : this.closable(true);
29624 this.fireEvent('refresh', this);
29627 onRemove : function(e, el, o)
29629 e.preventDefault();
29631 this.fireEvent('remove', this, o);
29635 remove : function(o)
29639 Roo.each(this.files, function(file){
29640 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29649 this.files = files;
29656 Roo.each(this.files, function(file){
29661 file.target.remove();
29670 onClick : function(e, el, o)
29672 e.preventDefault();
29674 this.fireEvent('click', this, o);
29678 closable : function(closable)
29680 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29682 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29694 xhrOnLoad : function(xhr)
29696 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29700 if (xhr.readyState !== 4) {
29702 this.fireEvent('exception', this, xhr);
29706 var response = Roo.decode(xhr.responseText);
29708 if(!response.success){
29710 this.fireEvent('exception', this, xhr);
29714 var file = this.renderPreview(response.data);
29716 this.files.push(file);
29720 this.fireEvent('afterupload', this, xhr);
29724 xhrOnError : function(xhr)
29726 Roo.log('xhr on error');
29728 var response = Roo.decode(xhr.responseText);
29735 process : function(file)
29737 if(this.fireEvent('process', this, file) !== false){
29738 if(this.editable && file.type.indexOf('image') != -1){
29739 this.fireEvent('edit', this, file);
29743 this.uploadStart(file, false);
29750 uploadStart : function(file, crop)
29752 this.xhr = new XMLHttpRequest();
29754 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29759 file.xhr = this.xhr;
29761 this.managerEl.createChild({
29763 cls : 'roo-document-manager-loading',
29767 tooltip : file.name,
29768 cls : 'roo-document-manager-thumb',
29769 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29775 this.xhr.open(this.method, this.url, true);
29778 "Accept": "application/json",
29779 "Cache-Control": "no-cache",
29780 "X-Requested-With": "XMLHttpRequest"
29783 for (var headerName in headers) {
29784 var headerValue = headers[headerName];
29786 this.xhr.setRequestHeader(headerName, headerValue);
29792 this.xhr.onload = function()
29794 _this.xhrOnLoad(_this.xhr);
29797 this.xhr.onerror = function()
29799 _this.xhrOnError(_this.xhr);
29802 var formData = new FormData();
29804 formData.append('returnHTML', 'NO');
29807 formData.append('crop', crop);
29810 formData.append(this.paramName, file, file.name);
29817 if(this.fireEvent('prepare', this, formData, options) != false){
29819 if(options.manually){
29823 this.xhr.send(formData);
29827 this.uploadCancel();
29830 uploadCancel : function()
29836 this.delegates = [];
29838 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29845 renderPreview : function(file)
29847 if(typeof(file.target) != 'undefined' && file.target){
29851 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29853 var previewEl = this.managerEl.createChild({
29855 cls : 'roo-document-manager-preview',
29859 tooltip : file[this.toolTipName],
29860 cls : 'roo-document-manager-thumb',
29861 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29866 html : '<i class="fa fa-times-circle"></i>'
29871 var close = previewEl.select('button.close', true).first();
29873 close.on('click', this.onRemove, this, file);
29875 file.target = previewEl;
29877 var image = previewEl.select('img', true).first();
29881 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29883 image.on('click', this.onClick, this, file);
29885 this.fireEvent('previewrendered', this, file);
29891 onPreviewLoad : function(file, image)
29893 if(typeof(file.target) == 'undefined' || !file.target){
29897 var width = image.dom.naturalWidth || image.dom.width;
29898 var height = image.dom.naturalHeight || image.dom.height;
29900 if(!this.previewResize) {
29904 if(width > height){
29905 file.target.addClass('wide');
29909 file.target.addClass('tall');
29914 uploadFromSource : function(file, crop)
29916 this.xhr = new XMLHttpRequest();
29918 this.managerEl.createChild({
29920 cls : 'roo-document-manager-loading',
29924 tooltip : file.name,
29925 cls : 'roo-document-manager-thumb',
29926 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29932 this.xhr.open(this.method, this.url, true);
29935 "Accept": "application/json",
29936 "Cache-Control": "no-cache",
29937 "X-Requested-With": "XMLHttpRequest"
29940 for (var headerName in headers) {
29941 var headerValue = headers[headerName];
29943 this.xhr.setRequestHeader(headerName, headerValue);
29949 this.xhr.onload = function()
29951 _this.xhrOnLoad(_this.xhr);
29954 this.xhr.onerror = function()
29956 _this.xhrOnError(_this.xhr);
29959 var formData = new FormData();
29961 formData.append('returnHTML', 'NO');
29963 formData.append('crop', crop);
29965 if(typeof(file.filename) != 'undefined'){
29966 formData.append('filename', file.filename);
29969 if(typeof(file.mimetype) != 'undefined'){
29970 formData.append('mimetype', file.mimetype);
29975 if(this.fireEvent('prepare', this, formData) != false){
29976 this.xhr.send(formData);
29986 * @class Roo.bootstrap.DocumentViewer
29987 * @extends Roo.bootstrap.Component
29988 * Bootstrap DocumentViewer class
29989 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29990 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29993 * Create a new DocumentViewer
29994 * @param {Object} config The config object
29997 Roo.bootstrap.DocumentViewer = function(config){
29998 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
30003 * Fire after initEvent
30004 * @param {Roo.bootstrap.DocumentViewer} this
30010 * @param {Roo.bootstrap.DocumentViewer} this
30015 * Fire after download button
30016 * @param {Roo.bootstrap.DocumentViewer} this
30021 * Fire after trash button
30022 * @param {Roo.bootstrap.DocumentViewer} this
30029 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
30031 showDownload : true,
30035 getAutoCreate : function()
30039 cls : 'roo-document-viewer',
30043 cls : 'roo-document-viewer-body',
30047 cls : 'roo-document-viewer-thumb',
30051 cls : 'roo-document-viewer-image'
30059 cls : 'roo-document-viewer-footer',
30062 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30066 cls : 'btn-group roo-document-viewer-download',
30070 cls : 'btn btn-default',
30071 html : '<i class="fa fa-download"></i>'
30077 cls : 'btn-group roo-document-viewer-trash',
30081 cls : 'btn btn-default',
30082 html : '<i class="fa fa-trash"></i>'
30095 initEvents : function()
30097 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30098 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30100 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30101 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30103 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30104 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30106 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30107 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30109 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30110 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30112 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30113 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30115 this.bodyEl.on('click', this.onClick, this);
30116 this.downloadBtn.on('click', this.onDownload, this);
30117 this.trashBtn.on('click', this.onTrash, this);
30119 this.downloadBtn.hide();
30120 this.trashBtn.hide();
30122 if(this.showDownload){
30123 this.downloadBtn.show();
30126 if(this.showTrash){
30127 this.trashBtn.show();
30130 if(!this.showDownload && !this.showTrash) {
30131 this.footerEl.hide();
30136 initial : function()
30138 this.fireEvent('initial', this);
30142 onClick : function(e)
30144 e.preventDefault();
30146 this.fireEvent('click', this);
30149 onDownload : function(e)
30151 e.preventDefault();
30153 this.fireEvent('download', this);
30156 onTrash : function(e)
30158 e.preventDefault();
30160 this.fireEvent('trash', this);
30172 * @class Roo.bootstrap.NavProgressBar
30173 * @extends Roo.bootstrap.Component
30174 * Bootstrap NavProgressBar class
30177 * Create a new nav progress bar
30178 * @param {Object} config The config object
30181 Roo.bootstrap.NavProgressBar = function(config){
30182 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30184 this.bullets = this.bullets || [];
30186 // Roo.bootstrap.NavProgressBar.register(this);
30190 * Fires when the active item changes
30191 * @param {Roo.bootstrap.NavProgressBar} this
30192 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30193 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30200 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30205 getAutoCreate : function()
30207 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30211 cls : 'roo-navigation-bar-group',
30215 cls : 'roo-navigation-top-bar'
30219 cls : 'roo-navigation-bullets-bar',
30223 cls : 'roo-navigation-bar'
30230 cls : 'roo-navigation-bottom-bar'
30240 initEvents: function()
30245 onRender : function(ct, position)
30247 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30249 if(this.bullets.length){
30250 Roo.each(this.bullets, function(b){
30259 addItem : function(cfg)
30261 var item = new Roo.bootstrap.NavProgressItem(cfg);
30263 item.parentId = this.id;
30264 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30267 var top = new Roo.bootstrap.Element({
30269 cls : 'roo-navigation-bar-text'
30272 var bottom = new Roo.bootstrap.Element({
30274 cls : 'roo-navigation-bar-text'
30277 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30278 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30280 var topText = new Roo.bootstrap.Element({
30282 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30285 var bottomText = new Roo.bootstrap.Element({
30287 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30290 topText.onRender(top.el, null);
30291 bottomText.onRender(bottom.el, null);
30294 item.bottomEl = bottom;
30297 this.barItems.push(item);
30302 getActive : function()
30304 var active = false;
30306 Roo.each(this.barItems, function(v){
30308 if (!v.isActive()) {
30320 setActiveItem : function(item)
30324 Roo.each(this.barItems, function(v){
30325 if (v.rid == item.rid) {
30329 if (v.isActive()) {
30330 v.setActive(false);
30335 item.setActive(true);
30337 this.fireEvent('changed', this, item, prev);
30340 getBarItem: function(rid)
30344 Roo.each(this.barItems, function(e) {
30345 if (e.rid != rid) {
30356 indexOfItem : function(item)
30360 Roo.each(this.barItems, function(v, i){
30362 if (v.rid != item.rid) {
30373 setActiveNext : function()
30375 var i = this.indexOfItem(this.getActive());
30377 if (i > this.barItems.length) {
30381 this.setActiveItem(this.barItems[i+1]);
30384 setActivePrev : function()
30386 var i = this.indexOfItem(this.getActive());
30392 this.setActiveItem(this.barItems[i-1]);
30395 format : function()
30397 if(!this.barItems.length){
30401 var width = 100 / this.barItems.length;
30403 Roo.each(this.barItems, function(i){
30404 i.el.setStyle('width', width + '%');
30405 i.topEl.el.setStyle('width', width + '%');
30406 i.bottomEl.el.setStyle('width', width + '%');
30415 * Nav Progress Item
30420 * @class Roo.bootstrap.NavProgressItem
30421 * @extends Roo.bootstrap.Component
30422 * Bootstrap NavProgressItem class
30423 * @cfg {String} rid the reference id
30424 * @cfg {Boolean} active (true|false) Is item active default false
30425 * @cfg {Boolean} disabled (true|false) Is item active default false
30426 * @cfg {String} html
30427 * @cfg {String} position (top|bottom) text position default bottom
30428 * @cfg {String} icon show icon instead of number
30431 * Create a new NavProgressItem
30432 * @param {Object} config The config object
30434 Roo.bootstrap.NavProgressItem = function(config){
30435 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30440 * The raw click event for the entire grid.
30441 * @param {Roo.bootstrap.NavProgressItem} this
30442 * @param {Roo.EventObject} e
30449 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30455 position : 'bottom',
30458 getAutoCreate : function()
30460 var iconCls = 'roo-navigation-bar-item-icon';
30462 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30466 cls: 'roo-navigation-bar-item',
30476 cfg.cls += ' active';
30479 cfg.cls += ' disabled';
30485 disable : function()
30487 this.setDisabled(true);
30490 enable : function()
30492 this.setDisabled(false);
30495 initEvents: function()
30497 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30499 this.iconEl.on('click', this.onClick, this);
30502 onClick : function(e)
30504 e.preventDefault();
30510 if(this.fireEvent('click', this, e) === false){
30514 this.parent().setActiveItem(this);
30517 isActive: function ()
30519 return this.active;
30522 setActive : function(state)
30524 if(this.active == state){
30528 this.active = state;
30531 this.el.addClass('active');
30535 this.el.removeClass('active');
30540 setDisabled : function(state)
30542 if(this.disabled == state){
30546 this.disabled = state;
30549 this.el.addClass('disabled');
30553 this.el.removeClass('disabled');
30556 tooltipEl : function()
30558 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30571 * @class Roo.bootstrap.FieldLabel
30572 * @extends Roo.bootstrap.Component
30573 * Bootstrap FieldLabel class
30574 * @cfg {String} html contents of the element
30575 * @cfg {String} tag tag of the element default label
30576 * @cfg {String} cls class of the element
30577 * @cfg {String} target label target
30578 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30579 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30580 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30581 * @cfg {String} iconTooltip default "This field is required"
30582 * @cfg {String} indicatorpos (left|right) default left
30585 * Create a new FieldLabel
30586 * @param {Object} config The config object
30589 Roo.bootstrap.FieldLabel = function(config){
30590 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30595 * Fires after the field has been marked as invalid.
30596 * @param {Roo.form.FieldLabel} this
30597 * @param {String} msg The validation message
30602 * Fires after the field has been validated with no errors.
30603 * @param {Roo.form.FieldLabel} this
30609 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30616 invalidClass : 'has-warning',
30617 validClass : 'has-success',
30618 iconTooltip : 'This field is required',
30619 indicatorpos : 'left',
30621 getAutoCreate : function(){
30624 if (!this.allowBlank) {
30630 cls : 'roo-bootstrap-field-label ' + this.cls,
30635 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30636 tooltip : this.iconTooltip
30645 if(this.indicatorpos == 'right'){
30648 cls : 'roo-bootstrap-field-label ' + this.cls,
30657 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30658 tooltip : this.iconTooltip
30667 initEvents: function()
30669 Roo.bootstrap.Element.superclass.initEvents.call(this);
30671 this.indicator = this.indicatorEl();
30673 if(this.indicator){
30674 this.indicator.removeClass('visible');
30675 this.indicator.addClass('invisible');
30678 Roo.bootstrap.FieldLabel.register(this);
30681 indicatorEl : function()
30683 var indicator = this.el.select('i.roo-required-indicator',true).first();
30694 * Mark this field as valid
30696 markValid : function()
30698 if(this.indicator){
30699 this.indicator.removeClass('visible');
30700 this.indicator.addClass('invisible');
30702 if (Roo.bootstrap.version == 3) {
30703 this.el.removeClass(this.invalidClass);
30704 this.el.addClass(this.validClass);
30706 this.el.removeClass('is-invalid');
30707 this.el.addClass('is-valid');
30711 this.fireEvent('valid', this);
30715 * Mark this field as invalid
30716 * @param {String} msg The validation message
30718 markInvalid : function(msg)
30720 if(this.indicator){
30721 this.indicator.removeClass('invisible');
30722 this.indicator.addClass('visible');
30724 if (Roo.bootstrap.version == 3) {
30725 this.el.removeClass(this.validClass);
30726 this.el.addClass(this.invalidClass);
30728 this.el.removeClass('is-valid');
30729 this.el.addClass('is-invalid');
30733 this.fireEvent('invalid', this, msg);
30739 Roo.apply(Roo.bootstrap.FieldLabel, {
30744 * register a FieldLabel Group
30745 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30747 register : function(label)
30749 if(this.groups.hasOwnProperty(label.target)){
30753 this.groups[label.target] = label;
30757 * fetch a FieldLabel Group based on the target
30758 * @param {string} target
30759 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30761 get: function(target) {
30762 if (typeof(this.groups[target]) == 'undefined') {
30766 return this.groups[target] ;
30775 * page DateSplitField.
30781 * @class Roo.bootstrap.DateSplitField
30782 * @extends Roo.bootstrap.Component
30783 * Bootstrap DateSplitField class
30784 * @cfg {string} fieldLabel - the label associated
30785 * @cfg {Number} labelWidth set the width of label (0-12)
30786 * @cfg {String} labelAlign (top|left)
30787 * @cfg {Boolean} dayAllowBlank (true|false) default false
30788 * @cfg {Boolean} monthAllowBlank (true|false) default false
30789 * @cfg {Boolean} yearAllowBlank (true|false) default false
30790 * @cfg {string} dayPlaceholder
30791 * @cfg {string} monthPlaceholder
30792 * @cfg {string} yearPlaceholder
30793 * @cfg {string} dayFormat default 'd'
30794 * @cfg {string} monthFormat default 'm'
30795 * @cfg {string} yearFormat default 'Y'
30796 * @cfg {Number} labellg set the width of label (1-12)
30797 * @cfg {Number} labelmd set the width of label (1-12)
30798 * @cfg {Number} labelsm set the width of label (1-12)
30799 * @cfg {Number} labelxs set the width of label (1-12)
30803 * Create a new DateSplitField
30804 * @param {Object} config The config object
30807 Roo.bootstrap.DateSplitField = function(config){
30808 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30814 * getting the data of years
30815 * @param {Roo.bootstrap.DateSplitField} this
30816 * @param {Object} years
30821 * getting the data of days
30822 * @param {Roo.bootstrap.DateSplitField} this
30823 * @param {Object} days
30828 * Fires after the field has been marked as invalid.
30829 * @param {Roo.form.Field} this
30830 * @param {String} msg The validation message
30835 * Fires after the field has been validated with no errors.
30836 * @param {Roo.form.Field} this
30842 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30845 labelAlign : 'top',
30847 dayAllowBlank : false,
30848 monthAllowBlank : false,
30849 yearAllowBlank : false,
30850 dayPlaceholder : '',
30851 monthPlaceholder : '',
30852 yearPlaceholder : '',
30856 isFormField : true,
30862 getAutoCreate : function()
30866 cls : 'row roo-date-split-field-group',
30871 cls : 'form-hidden-field roo-date-split-field-group-value',
30877 var labelCls = 'col-md-12';
30878 var contentCls = 'col-md-4';
30880 if(this.fieldLabel){
30884 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30888 html : this.fieldLabel
30893 if(this.labelAlign == 'left'){
30895 if(this.labelWidth > 12){
30896 label.style = "width: " + this.labelWidth + 'px';
30899 if(this.labelWidth < 13 && this.labelmd == 0){
30900 this.labelmd = this.labelWidth;
30903 if(this.labellg > 0){
30904 labelCls = ' col-lg-' + this.labellg;
30905 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30908 if(this.labelmd > 0){
30909 labelCls = ' col-md-' + this.labelmd;
30910 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30913 if(this.labelsm > 0){
30914 labelCls = ' col-sm-' + this.labelsm;
30915 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30918 if(this.labelxs > 0){
30919 labelCls = ' col-xs-' + this.labelxs;
30920 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30924 label.cls += ' ' + labelCls;
30926 cfg.cn.push(label);
30929 Roo.each(['day', 'month', 'year'], function(t){
30932 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30939 inputEl: function ()
30941 return this.el.select('.roo-date-split-field-group-value', true).first();
30944 onRender : function(ct, position)
30948 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30950 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30952 this.dayField = new Roo.bootstrap.ComboBox({
30953 allowBlank : this.dayAllowBlank,
30954 alwaysQuery : true,
30955 displayField : 'value',
30958 forceSelection : true,
30960 placeholder : this.dayPlaceholder,
30961 selectOnFocus : true,
30962 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30963 triggerAction : 'all',
30965 valueField : 'value',
30966 store : new Roo.data.SimpleStore({
30967 data : (function() {
30969 _this.fireEvent('days', _this, days);
30972 fields : [ 'value' ]
30975 select : function (_self, record, index)
30977 _this.setValue(_this.getValue());
30982 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30984 this.monthField = new Roo.bootstrap.MonthField({
30985 after : '<i class=\"fa fa-calendar\"></i>',
30986 allowBlank : this.monthAllowBlank,
30987 placeholder : this.monthPlaceholder,
30990 render : function (_self)
30992 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30993 e.preventDefault();
30997 select : function (_self, oldvalue, newvalue)
30999 _this.setValue(_this.getValue());
31004 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
31006 this.yearField = new Roo.bootstrap.ComboBox({
31007 allowBlank : this.yearAllowBlank,
31008 alwaysQuery : true,
31009 displayField : 'value',
31012 forceSelection : true,
31014 placeholder : this.yearPlaceholder,
31015 selectOnFocus : true,
31016 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
31017 triggerAction : 'all',
31019 valueField : 'value',
31020 store : new Roo.data.SimpleStore({
31021 data : (function() {
31023 _this.fireEvent('years', _this, years);
31026 fields : [ 'value' ]
31029 select : function (_self, record, index)
31031 _this.setValue(_this.getValue());
31036 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
31039 setValue : function(v, format)
31041 this.inputEl.dom.value = v;
31043 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
31045 var d = Date.parseDate(v, f);
31052 this.setDay(d.format(this.dayFormat));
31053 this.setMonth(d.format(this.monthFormat));
31054 this.setYear(d.format(this.yearFormat));
31061 setDay : function(v)
31063 this.dayField.setValue(v);
31064 this.inputEl.dom.value = this.getValue();
31069 setMonth : function(v)
31071 this.monthField.setValue(v, true);
31072 this.inputEl.dom.value = this.getValue();
31077 setYear : function(v)
31079 this.yearField.setValue(v);
31080 this.inputEl.dom.value = this.getValue();
31085 getDay : function()
31087 return this.dayField.getValue();
31090 getMonth : function()
31092 return this.monthField.getValue();
31095 getYear : function()
31097 return this.yearField.getValue();
31100 getValue : function()
31102 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31104 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31114 this.inputEl.dom.value = '';
31119 validate : function()
31121 var d = this.dayField.validate();
31122 var m = this.monthField.validate();
31123 var y = this.yearField.validate();
31128 (!this.dayAllowBlank && !d) ||
31129 (!this.monthAllowBlank && !m) ||
31130 (!this.yearAllowBlank && !y)
31135 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31144 this.markInvalid();
31149 markValid : function()
31152 var label = this.el.select('label', true).first();
31153 var icon = this.el.select('i.fa-star', true).first();
31159 this.fireEvent('valid', this);
31163 * Mark this field as invalid
31164 * @param {String} msg The validation message
31166 markInvalid : function(msg)
31169 var label = this.el.select('label', true).first();
31170 var icon = this.el.select('i.fa-star', true).first();
31172 if(label && !icon){
31173 this.el.select('.roo-date-split-field-label', true).createChild({
31175 cls : 'text-danger fa fa-lg fa-star',
31176 tooltip : 'This field is required',
31177 style : 'margin-right:5px;'
31181 this.fireEvent('invalid', this, msg);
31184 clearInvalid : function()
31186 var label = this.el.select('label', true).first();
31187 var icon = this.el.select('i.fa-star', true).first();
31193 this.fireEvent('valid', this);
31196 getName: function()
31206 * http://masonry.desandro.com
31208 * The idea is to render all the bricks based on vertical width...
31210 * The original code extends 'outlayer' - we might need to use that....
31216 * @class Roo.bootstrap.LayoutMasonry
31217 * @extends Roo.bootstrap.Component
31218 * Bootstrap Layout Masonry class
31221 * Create a new Element
31222 * @param {Object} config The config object
31225 Roo.bootstrap.LayoutMasonry = function(config){
31227 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31231 Roo.bootstrap.LayoutMasonry.register(this);
31237 * Fire after layout the items
31238 * @param {Roo.bootstrap.LayoutMasonry} this
31239 * @param {Roo.EventObject} e
31246 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31249 * @cfg {Boolean} isLayoutInstant = no animation?
31251 isLayoutInstant : false, // needed?
31254 * @cfg {Number} boxWidth width of the columns
31259 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31264 * @cfg {Number} padWidth padding below box..
31269 * @cfg {Number} gutter gutter width..
31274 * @cfg {Number} maxCols maximum number of columns
31280 * @cfg {Boolean} isAutoInitial defalut true
31282 isAutoInitial : true,
31287 * @cfg {Boolean} isHorizontal defalut false
31289 isHorizontal : false,
31291 currentSize : null,
31297 bricks: null, //CompositeElement
31301 _isLayoutInited : false,
31303 // isAlternative : false, // only use for vertical layout...
31306 * @cfg {Number} alternativePadWidth padding below box..
31308 alternativePadWidth : 50,
31310 selectedBrick : [],
31312 getAutoCreate : function(){
31314 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31318 cls: 'blog-masonary-wrapper ' + this.cls,
31320 cls : 'mas-boxes masonary'
31327 getChildContainer: function( )
31329 if (this.boxesEl) {
31330 return this.boxesEl;
31333 this.boxesEl = this.el.select('.mas-boxes').first();
31335 return this.boxesEl;
31339 initEvents : function()
31343 if(this.isAutoInitial){
31344 Roo.log('hook children rendered');
31345 this.on('childrenrendered', function() {
31346 Roo.log('children rendered');
31352 initial : function()
31354 this.selectedBrick = [];
31356 this.currentSize = this.el.getBox(true);
31358 Roo.EventManager.onWindowResize(this.resize, this);
31360 if(!this.isAutoInitial){
31368 //this.layout.defer(500,this);
31372 resize : function()
31374 var cs = this.el.getBox(true);
31377 this.currentSize.width == cs.width &&
31378 this.currentSize.x == cs.x &&
31379 this.currentSize.height == cs.height &&
31380 this.currentSize.y == cs.y
31382 Roo.log("no change in with or X or Y");
31386 this.currentSize = cs;
31392 layout : function()
31394 this._resetLayout();
31396 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31398 this.layoutItems( isInstant );
31400 this._isLayoutInited = true;
31402 this.fireEvent('layout', this);
31406 _resetLayout : function()
31408 if(this.isHorizontal){
31409 this.horizontalMeasureColumns();
31413 this.verticalMeasureColumns();
31417 verticalMeasureColumns : function()
31419 this.getContainerWidth();
31421 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31422 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31426 var boxWidth = this.boxWidth + this.padWidth;
31428 if(this.containerWidth < this.boxWidth){
31429 boxWidth = this.containerWidth
31432 var containerWidth = this.containerWidth;
31434 var cols = Math.floor(containerWidth / boxWidth);
31436 this.cols = Math.max( cols, 1 );
31438 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31440 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31442 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31444 this.colWidth = boxWidth + avail - this.padWidth;
31446 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31447 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31450 horizontalMeasureColumns : function()
31452 this.getContainerWidth();
31454 var boxWidth = this.boxWidth;
31456 if(this.containerWidth < boxWidth){
31457 boxWidth = this.containerWidth;
31460 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31462 this.el.setHeight(boxWidth);
31466 getContainerWidth : function()
31468 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31471 layoutItems : function( isInstant )
31473 Roo.log(this.bricks);
31475 var items = Roo.apply([], this.bricks);
31477 if(this.isHorizontal){
31478 this._horizontalLayoutItems( items , isInstant );
31482 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31483 // this._verticalAlternativeLayoutItems( items , isInstant );
31487 this._verticalLayoutItems( items , isInstant );
31491 _verticalLayoutItems : function ( items , isInstant)
31493 if ( !items || !items.length ) {
31498 ['xs', 'xs', 'xs', 'tall'],
31499 ['xs', 'xs', 'tall'],
31500 ['xs', 'xs', 'sm'],
31501 ['xs', 'xs', 'xs'],
31507 ['sm', 'xs', 'xs'],
31511 ['tall', 'xs', 'xs', 'xs'],
31512 ['tall', 'xs', 'xs'],
31524 Roo.each(items, function(item, k){
31526 switch (item.size) {
31527 // these layouts take up a full box,
31538 boxes.push([item]);
31561 var filterPattern = function(box, length)
31569 var pattern = box.slice(0, length);
31573 Roo.each(pattern, function(i){
31574 format.push(i.size);
31577 Roo.each(standard, function(s){
31579 if(String(s) != String(format)){
31588 if(!match && length == 1){
31593 filterPattern(box, length - 1);
31597 queue.push(pattern);
31599 box = box.slice(length, box.length);
31601 filterPattern(box, 4);
31607 Roo.each(boxes, function(box, k){
31613 if(box.length == 1){
31618 filterPattern(box, 4);
31622 this._processVerticalLayoutQueue( queue, isInstant );
31626 // _verticalAlternativeLayoutItems : function( items , isInstant )
31628 // if ( !items || !items.length ) {
31632 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31636 _horizontalLayoutItems : function ( items , isInstant)
31638 if ( !items || !items.length || items.length < 3) {
31644 var eItems = items.slice(0, 3);
31646 items = items.slice(3, items.length);
31649 ['xs', 'xs', 'xs', 'wide'],
31650 ['xs', 'xs', 'wide'],
31651 ['xs', 'xs', 'sm'],
31652 ['xs', 'xs', 'xs'],
31658 ['sm', 'xs', 'xs'],
31662 ['wide', 'xs', 'xs', 'xs'],
31663 ['wide', 'xs', 'xs'],
31676 Roo.each(items, function(item, k){
31678 switch (item.size) {
31689 boxes.push([item]);
31713 var filterPattern = function(box, length)
31721 var pattern = box.slice(0, length);
31725 Roo.each(pattern, function(i){
31726 format.push(i.size);
31729 Roo.each(standard, function(s){
31731 if(String(s) != String(format)){
31740 if(!match && length == 1){
31745 filterPattern(box, length - 1);
31749 queue.push(pattern);
31751 box = box.slice(length, box.length);
31753 filterPattern(box, 4);
31759 Roo.each(boxes, function(box, k){
31765 if(box.length == 1){
31770 filterPattern(box, 4);
31777 var pos = this.el.getBox(true);
31781 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31783 var hit_end = false;
31785 Roo.each(queue, function(box){
31789 Roo.each(box, function(b){
31791 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31801 Roo.each(box, function(b){
31803 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31806 mx = Math.max(mx, b.x);
31810 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31814 Roo.each(box, function(b){
31816 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31830 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31833 /** Sets position of item in DOM
31834 * @param {Element} item
31835 * @param {Number} x - horizontal position
31836 * @param {Number} y - vertical position
31837 * @param {Boolean} isInstant - disables transitions
31839 _processVerticalLayoutQueue : function( queue, isInstant )
31841 var pos = this.el.getBox(true);
31846 for (var i = 0; i < this.cols; i++){
31850 Roo.each(queue, function(box, k){
31852 var col = k % this.cols;
31854 Roo.each(box, function(b,kk){
31856 b.el.position('absolute');
31858 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31859 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31861 if(b.size == 'md-left' || b.size == 'md-right'){
31862 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31863 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31866 b.el.setWidth(width);
31867 b.el.setHeight(height);
31869 b.el.select('iframe',true).setSize(width,height);
31873 for (var i = 0; i < this.cols; i++){
31875 if(maxY[i] < maxY[col]){
31880 col = Math.min(col, i);
31884 x = pos.x + col * (this.colWidth + this.padWidth);
31888 var positions = [];
31890 switch (box.length){
31892 positions = this.getVerticalOneBoxColPositions(x, y, box);
31895 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31898 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31901 positions = this.getVerticalFourBoxColPositions(x, y, box);
31907 Roo.each(box, function(b,kk){
31909 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31911 var sz = b.el.getSize();
31913 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31921 for (var i = 0; i < this.cols; i++){
31922 mY = Math.max(mY, maxY[i]);
31925 this.el.setHeight(mY - pos.y);
31929 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31931 // var pos = this.el.getBox(true);
31934 // var maxX = pos.right;
31936 // var maxHeight = 0;
31938 // Roo.each(items, function(item, k){
31942 // item.el.position('absolute');
31944 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31946 // item.el.setWidth(width);
31948 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31950 // item.el.setHeight(height);
31953 // item.el.setXY([x, y], isInstant ? false : true);
31955 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31958 // y = y + height + this.alternativePadWidth;
31960 // maxHeight = maxHeight + height + this.alternativePadWidth;
31964 // this.el.setHeight(maxHeight);
31968 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31970 var pos = this.el.getBox(true);
31975 var maxX = pos.right;
31977 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31979 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31981 Roo.each(queue, function(box, k){
31983 Roo.each(box, function(b, kk){
31985 b.el.position('absolute');
31987 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31988 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31990 if(b.size == 'md-left' || b.size == 'md-right'){
31991 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31992 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31995 b.el.setWidth(width);
31996 b.el.setHeight(height);
32004 var positions = [];
32006 switch (box.length){
32008 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
32011 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
32014 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
32017 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
32023 Roo.each(box, function(b,kk){
32025 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
32027 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
32035 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
32037 Roo.each(eItems, function(b,k){
32039 b.size = (k == 0) ? 'sm' : 'xs';
32040 b.x = (k == 0) ? 2 : 1;
32041 b.y = (k == 0) ? 2 : 1;
32043 b.el.position('absolute');
32045 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32047 b.el.setWidth(width);
32049 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32051 b.el.setHeight(height);
32055 var positions = [];
32058 x : maxX - this.unitWidth * 2 - this.gutter,
32063 x : maxX - this.unitWidth,
32064 y : minY + (this.unitWidth + this.gutter) * 2
32068 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32072 Roo.each(eItems, function(b,k){
32074 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32080 getVerticalOneBoxColPositions : function(x, y, box)
32084 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32086 if(box[0].size == 'md-left'){
32090 if(box[0].size == 'md-right'){
32095 x : x + (this.unitWidth + this.gutter) * rand,
32102 getVerticalTwoBoxColPositions : function(x, y, box)
32106 if(box[0].size == 'xs'){
32110 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32114 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32128 x : x + (this.unitWidth + this.gutter) * 2,
32129 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32136 getVerticalThreeBoxColPositions : function(x, y, box)
32140 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32148 x : x + (this.unitWidth + this.gutter) * 1,
32153 x : x + (this.unitWidth + this.gutter) * 2,
32161 if(box[0].size == 'xs' && box[1].size == 'xs'){
32170 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32174 x : x + (this.unitWidth + this.gutter) * 1,
32188 x : x + (this.unitWidth + this.gutter) * 2,
32193 x : x + (this.unitWidth + this.gutter) * 2,
32194 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32201 getVerticalFourBoxColPositions : function(x, y, box)
32205 if(box[0].size == 'xs'){
32214 y : y + (this.unitHeight + this.gutter) * 1
32219 y : y + (this.unitHeight + this.gutter) * 2
32223 x : x + (this.unitWidth + this.gutter) * 1,
32237 x : x + (this.unitWidth + this.gutter) * 2,
32242 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32243 y : y + (this.unitHeight + this.gutter) * 1
32247 x : x + (this.unitWidth + this.gutter) * 2,
32248 y : y + (this.unitWidth + this.gutter) * 2
32255 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32259 if(box[0].size == 'md-left'){
32261 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32268 if(box[0].size == 'md-right'){
32270 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32271 y : minY + (this.unitWidth + this.gutter) * 1
32277 var rand = Math.floor(Math.random() * (4 - box[0].y));
32280 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32281 y : minY + (this.unitWidth + this.gutter) * rand
32288 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32292 if(box[0].size == 'xs'){
32295 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32300 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32301 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32309 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32314 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32315 y : minY + (this.unitWidth + this.gutter) * 2
32322 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32326 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32329 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32334 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32335 y : minY + (this.unitWidth + this.gutter) * 1
32339 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32340 y : minY + (this.unitWidth + this.gutter) * 2
32347 if(box[0].size == 'xs' && box[1].size == 'xs'){
32350 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32355 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32360 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32361 y : minY + (this.unitWidth + this.gutter) * 1
32369 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32374 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32375 y : minY + (this.unitWidth + this.gutter) * 2
32379 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32380 y : minY + (this.unitWidth + this.gutter) * 2
32387 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32391 if(box[0].size == 'xs'){
32394 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32399 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32404 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),
32409 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32410 y : minY + (this.unitWidth + this.gutter) * 1
32418 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32423 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32424 y : minY + (this.unitWidth + this.gutter) * 2
32428 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32429 y : minY + (this.unitWidth + this.gutter) * 2
32433 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),
32434 y : minY + (this.unitWidth + this.gutter) * 2
32442 * remove a Masonry Brick
32443 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32445 removeBrick : function(brick_id)
32451 for (var i = 0; i<this.bricks.length; i++) {
32452 if (this.bricks[i].id == brick_id) {
32453 this.bricks.splice(i,1);
32454 this.el.dom.removeChild(Roo.get(brick_id).dom);
32461 * adds a Masonry Brick
32462 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32464 addBrick : function(cfg)
32466 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32467 //this.register(cn);
32468 cn.parentId = this.id;
32469 cn.render(this.el);
32474 * register a Masonry Brick
32475 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32478 register : function(brick)
32480 this.bricks.push(brick);
32481 brick.masonryId = this.id;
32485 * clear all the Masonry Brick
32487 clearAll : function()
32490 //this.getChildContainer().dom.innerHTML = "";
32491 this.el.dom.innerHTML = '';
32494 getSelected : function()
32496 if (!this.selectedBrick) {
32500 return this.selectedBrick;
32504 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32508 * register a Masonry Layout
32509 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32512 register : function(layout)
32514 this.groups[layout.id] = layout;
32517 * fetch a Masonry Layout based on the masonry layout ID
32518 * @param {string} the masonry layout to add
32519 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32522 get: function(layout_id) {
32523 if (typeof(this.groups[layout_id]) == 'undefined') {
32526 return this.groups[layout_id] ;
32538 * http://masonry.desandro.com
32540 * The idea is to render all the bricks based on vertical width...
32542 * The original code extends 'outlayer' - we might need to use that....
32548 * @class Roo.bootstrap.LayoutMasonryAuto
32549 * @extends Roo.bootstrap.Component
32550 * Bootstrap Layout Masonry class
32553 * Create a new Element
32554 * @param {Object} config The config object
32557 Roo.bootstrap.LayoutMasonryAuto = function(config){
32558 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32561 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32564 * @cfg {Boolean} isFitWidth - resize the width..
32566 isFitWidth : false, // options..
32568 * @cfg {Boolean} isOriginLeft = left align?
32570 isOriginLeft : true,
32572 * @cfg {Boolean} isOriginTop = top align?
32574 isOriginTop : false,
32576 * @cfg {Boolean} isLayoutInstant = no animation?
32578 isLayoutInstant : false, // needed?
32580 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32582 isResizingContainer : true,
32584 * @cfg {Number} columnWidth width of the columns
32590 * @cfg {Number} maxCols maximum number of columns
32595 * @cfg {Number} padHeight padding below box..
32601 * @cfg {Boolean} isAutoInitial defalut true
32604 isAutoInitial : true,
32610 initialColumnWidth : 0,
32611 currentSize : null,
32613 colYs : null, // array.
32620 bricks: null, //CompositeElement
32621 cols : 0, // array?
32622 // element : null, // wrapped now this.el
32623 _isLayoutInited : null,
32626 getAutoCreate : function(){
32630 cls: 'blog-masonary-wrapper ' + this.cls,
32632 cls : 'mas-boxes masonary'
32639 getChildContainer: function( )
32641 if (this.boxesEl) {
32642 return this.boxesEl;
32645 this.boxesEl = this.el.select('.mas-boxes').first();
32647 return this.boxesEl;
32651 initEvents : function()
32655 if(this.isAutoInitial){
32656 Roo.log('hook children rendered');
32657 this.on('childrenrendered', function() {
32658 Roo.log('children rendered');
32665 initial : function()
32667 this.reloadItems();
32669 this.currentSize = this.el.getBox(true);
32671 /// was window resize... - let's see if this works..
32672 Roo.EventManager.onWindowResize(this.resize, this);
32674 if(!this.isAutoInitial){
32679 this.layout.defer(500,this);
32682 reloadItems: function()
32684 this.bricks = this.el.select('.masonry-brick', true);
32686 this.bricks.each(function(b) {
32687 //Roo.log(b.getSize());
32688 if (!b.attr('originalwidth')) {
32689 b.attr('originalwidth', b.getSize().width);
32694 Roo.log(this.bricks.elements.length);
32697 resize : function()
32700 var cs = this.el.getBox(true);
32702 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32703 Roo.log("no change in with or X");
32706 this.currentSize = cs;
32710 layout : function()
32713 this._resetLayout();
32714 //this._manageStamps();
32716 // don't animate first layout
32717 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32718 this.layoutItems( isInstant );
32720 // flag for initalized
32721 this._isLayoutInited = true;
32724 layoutItems : function( isInstant )
32726 //var items = this._getItemsForLayout( this.items );
32727 // original code supports filtering layout items.. we just ignore it..
32729 this._layoutItems( this.bricks , isInstant );
32731 this._postLayout();
32733 _layoutItems : function ( items , isInstant)
32735 //this.fireEvent( 'layout', this, items );
32738 if ( !items || !items.elements.length ) {
32739 // no items, emit event with empty array
32744 items.each(function(item) {
32745 Roo.log("layout item");
32747 // get x/y object from method
32748 var position = this._getItemLayoutPosition( item );
32750 position.item = item;
32751 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32752 queue.push( position );
32755 this._processLayoutQueue( queue );
32757 /** Sets position of item in DOM
32758 * @param {Element} item
32759 * @param {Number} x - horizontal position
32760 * @param {Number} y - vertical position
32761 * @param {Boolean} isInstant - disables transitions
32763 _processLayoutQueue : function( queue )
32765 for ( var i=0, len = queue.length; i < len; i++ ) {
32766 var obj = queue[i];
32767 obj.item.position('absolute');
32768 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32774 * Any logic you want to do after each layout,
32775 * i.e. size the container
32777 _postLayout : function()
32779 this.resizeContainer();
32782 resizeContainer : function()
32784 if ( !this.isResizingContainer ) {
32787 var size = this._getContainerSize();
32789 this.el.setSize(size.width,size.height);
32790 this.boxesEl.setSize(size.width,size.height);
32796 _resetLayout : function()
32798 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32799 this.colWidth = this.el.getWidth();
32800 //this.gutter = this.el.getWidth();
32802 this.measureColumns();
32808 this.colYs.push( 0 );
32814 measureColumns : function()
32816 this.getContainerWidth();
32817 // if columnWidth is 0, default to outerWidth of first item
32818 if ( !this.columnWidth ) {
32819 var firstItem = this.bricks.first();
32820 Roo.log(firstItem);
32821 this.columnWidth = this.containerWidth;
32822 if (firstItem && firstItem.attr('originalwidth') ) {
32823 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32825 // columnWidth fall back to item of first element
32826 Roo.log("set column width?");
32827 this.initialColumnWidth = this.columnWidth ;
32829 // if first elem has no width, default to size of container
32834 if (this.initialColumnWidth) {
32835 this.columnWidth = this.initialColumnWidth;
32840 // column width is fixed at the top - however if container width get's smaller we should
32843 // this bit calcs how man columns..
32845 var columnWidth = this.columnWidth += this.gutter;
32847 // calculate columns
32848 var containerWidth = this.containerWidth + this.gutter;
32850 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32851 // fix rounding errors, typically with gutters
32852 var excess = columnWidth - containerWidth % columnWidth;
32855 // if overshoot is less than a pixel, round up, otherwise floor it
32856 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32857 cols = Math[ mathMethod ]( cols );
32858 this.cols = Math.max( cols, 1 );
32859 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32861 // padding positioning..
32862 var totalColWidth = this.cols * this.columnWidth;
32863 var padavail = this.containerWidth - totalColWidth;
32864 // so for 2 columns - we need 3 'pads'
32866 var padNeeded = (1+this.cols) * this.padWidth;
32868 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32870 this.columnWidth += padExtra
32871 //this.padWidth = Math.floor(padavail / ( this.cols));
32873 // adjust colum width so that padding is fixed??
32875 // we have 3 columns ... total = width * 3
32876 // we have X left over... that should be used by
32878 //if (this.expandC) {
32886 getContainerWidth : function()
32888 /* // container is parent if fit width
32889 var container = this.isFitWidth ? this.element.parentNode : this.element;
32890 // check that this.size and size are there
32891 // IE8 triggers resize on body size change, so they might not be
32893 var size = getSize( container ); //FIXME
32894 this.containerWidth = size && size.innerWidth; //FIXME
32897 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32901 _getItemLayoutPosition : function( item ) // what is item?
32903 // we resize the item to our columnWidth..
32905 item.setWidth(this.columnWidth);
32906 item.autoBoxAdjust = false;
32908 var sz = item.getSize();
32910 // how many columns does this brick span
32911 var remainder = this.containerWidth % this.columnWidth;
32913 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32914 // round if off by 1 pixel, otherwise use ceil
32915 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32916 colSpan = Math.min( colSpan, this.cols );
32918 // normally this should be '1' as we dont' currently allow multi width columns..
32920 var colGroup = this._getColGroup( colSpan );
32921 // get the minimum Y value from the columns
32922 var minimumY = Math.min.apply( Math, colGroup );
32923 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32925 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32927 // position the brick
32929 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32930 y: this.currentSize.y + minimumY + this.padHeight
32934 // apply setHeight to necessary columns
32935 var setHeight = minimumY + sz.height + this.padHeight;
32936 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32938 var setSpan = this.cols + 1 - colGroup.length;
32939 for ( var i = 0; i < setSpan; i++ ) {
32940 this.colYs[ shortColIndex + i ] = setHeight ;
32947 * @param {Number} colSpan - number of columns the element spans
32948 * @returns {Array} colGroup
32950 _getColGroup : function( colSpan )
32952 if ( colSpan < 2 ) {
32953 // if brick spans only one column, use all the column Ys
32958 // how many different places could this brick fit horizontally
32959 var groupCount = this.cols + 1 - colSpan;
32960 // for each group potential horizontal position
32961 for ( var i = 0; i < groupCount; i++ ) {
32962 // make an array of colY values for that one group
32963 var groupColYs = this.colYs.slice( i, i + colSpan );
32964 // and get the max value of the array
32965 colGroup[i] = Math.max.apply( Math, groupColYs );
32970 _manageStamp : function( stamp )
32972 var stampSize = stamp.getSize();
32973 var offset = stamp.getBox();
32974 // get the columns that this stamp affects
32975 var firstX = this.isOriginLeft ? offset.x : offset.right;
32976 var lastX = firstX + stampSize.width;
32977 var firstCol = Math.floor( firstX / this.columnWidth );
32978 firstCol = Math.max( 0, firstCol );
32980 var lastCol = Math.floor( lastX / this.columnWidth );
32981 // lastCol should not go over if multiple of columnWidth #425
32982 lastCol -= lastX % this.columnWidth ? 0 : 1;
32983 lastCol = Math.min( this.cols - 1, lastCol );
32985 // set colYs to bottom of the stamp
32986 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32989 for ( var i = firstCol; i <= lastCol; i++ ) {
32990 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32995 _getContainerSize : function()
32997 this.maxY = Math.max.apply( Math, this.colYs );
33002 if ( this.isFitWidth ) {
33003 size.width = this._getContainerFitWidth();
33009 _getContainerFitWidth : function()
33011 var unusedCols = 0;
33012 // count unused columns
33015 if ( this.colYs[i] !== 0 ) {
33020 // fit container to columns that have been used
33021 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
33024 needsResizeLayout : function()
33026 var previousWidth = this.containerWidth;
33027 this.getContainerWidth();
33028 return previousWidth !== this.containerWidth;
33043 * @class Roo.bootstrap.MasonryBrick
33044 * @extends Roo.bootstrap.Component
33045 * Bootstrap MasonryBrick class
33048 * Create a new MasonryBrick
33049 * @param {Object} config The config object
33052 Roo.bootstrap.MasonryBrick = function(config){
33054 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
33056 Roo.bootstrap.MasonryBrick.register(this);
33062 * When a MasonryBrick is clcik
33063 * @param {Roo.bootstrap.MasonryBrick} this
33064 * @param {Roo.EventObject} e
33070 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33073 * @cfg {String} title
33077 * @cfg {String} html
33081 * @cfg {String} bgimage
33085 * @cfg {String} videourl
33089 * @cfg {String} cls
33093 * @cfg {String} href
33097 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33102 * @cfg {String} placetitle (center|bottom)
33107 * @cfg {Boolean} isFitContainer defalut true
33109 isFitContainer : true,
33112 * @cfg {Boolean} preventDefault defalut false
33114 preventDefault : false,
33117 * @cfg {Boolean} inverse defalut false
33119 maskInverse : false,
33121 getAutoCreate : function()
33123 if(!this.isFitContainer){
33124 return this.getSplitAutoCreate();
33127 var cls = 'masonry-brick masonry-brick-full';
33129 if(this.href.length){
33130 cls += ' masonry-brick-link';
33133 if(this.bgimage.length){
33134 cls += ' masonry-brick-image';
33137 if(this.maskInverse){
33138 cls += ' mask-inverse';
33141 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33142 cls += ' enable-mask';
33146 cls += ' masonry-' + this.size + '-brick';
33149 if(this.placetitle.length){
33151 switch (this.placetitle) {
33153 cls += ' masonry-center-title';
33156 cls += ' masonry-bottom-title';
33163 if(!this.html.length && !this.bgimage.length){
33164 cls += ' masonry-center-title';
33167 if(!this.html.length && this.bgimage.length){
33168 cls += ' masonry-bottom-title';
33173 cls += ' ' + this.cls;
33177 tag: (this.href.length) ? 'a' : 'div',
33182 cls: 'masonry-brick-mask'
33186 cls: 'masonry-brick-paragraph',
33192 if(this.href.length){
33193 cfg.href = this.href;
33196 var cn = cfg.cn[1].cn;
33198 if(this.title.length){
33201 cls: 'masonry-brick-title',
33206 if(this.html.length){
33209 cls: 'masonry-brick-text',
33214 if (!this.title.length && !this.html.length) {
33215 cfg.cn[1].cls += ' hide';
33218 if(this.bgimage.length){
33221 cls: 'masonry-brick-image-view',
33226 if(this.videourl.length){
33227 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33228 // youtube support only?
33231 cls: 'masonry-brick-image-view',
33234 allowfullscreen : true
33242 getSplitAutoCreate : function()
33244 var cls = 'masonry-brick masonry-brick-split';
33246 if(this.href.length){
33247 cls += ' masonry-brick-link';
33250 if(this.bgimage.length){
33251 cls += ' masonry-brick-image';
33255 cls += ' masonry-' + this.size + '-brick';
33258 switch (this.placetitle) {
33260 cls += ' masonry-center-title';
33263 cls += ' masonry-bottom-title';
33266 if(!this.bgimage.length){
33267 cls += ' masonry-center-title';
33270 if(this.bgimage.length){
33271 cls += ' masonry-bottom-title';
33277 cls += ' ' + this.cls;
33281 tag: (this.href.length) ? 'a' : 'div',
33286 cls: 'masonry-brick-split-head',
33290 cls: 'masonry-brick-paragraph',
33297 cls: 'masonry-brick-split-body',
33303 if(this.href.length){
33304 cfg.href = this.href;
33307 if(this.title.length){
33308 cfg.cn[0].cn[0].cn.push({
33310 cls: 'masonry-brick-title',
33315 if(this.html.length){
33316 cfg.cn[1].cn.push({
33318 cls: 'masonry-brick-text',
33323 if(this.bgimage.length){
33324 cfg.cn[0].cn.push({
33326 cls: 'masonry-brick-image-view',
33331 if(this.videourl.length){
33332 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33333 // youtube support only?
33334 cfg.cn[0].cn.cn.push({
33336 cls: 'masonry-brick-image-view',
33339 allowfullscreen : true
33346 initEvents: function()
33348 switch (this.size) {
33381 this.el.on('touchstart', this.onTouchStart, this);
33382 this.el.on('touchmove', this.onTouchMove, this);
33383 this.el.on('touchend', this.onTouchEnd, this);
33384 this.el.on('contextmenu', this.onContextMenu, this);
33386 this.el.on('mouseenter' ,this.enter, this);
33387 this.el.on('mouseleave', this.leave, this);
33388 this.el.on('click', this.onClick, this);
33391 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33392 this.parent().bricks.push(this);
33397 onClick: function(e, el)
33399 var time = this.endTimer - this.startTimer;
33400 // Roo.log(e.preventDefault());
33403 e.preventDefault();
33408 if(!this.preventDefault){
33412 e.preventDefault();
33414 if (this.activeClass != '') {
33415 this.selectBrick();
33418 this.fireEvent('click', this, e);
33421 enter: function(e, el)
33423 e.preventDefault();
33425 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33429 if(this.bgimage.length && this.html.length){
33430 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33434 leave: function(e, el)
33436 e.preventDefault();
33438 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33442 if(this.bgimage.length && this.html.length){
33443 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33447 onTouchStart: function(e, el)
33449 // e.preventDefault();
33451 this.touchmoved = false;
33453 if(!this.isFitContainer){
33457 if(!this.bgimage.length || !this.html.length){
33461 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33463 this.timer = new Date().getTime();
33467 onTouchMove: function(e, el)
33469 this.touchmoved = true;
33472 onContextMenu : function(e,el)
33474 e.preventDefault();
33475 e.stopPropagation();
33479 onTouchEnd: function(e, el)
33481 // e.preventDefault();
33483 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33490 if(!this.bgimage.length || !this.html.length){
33492 if(this.href.length){
33493 window.location.href = this.href;
33499 if(!this.isFitContainer){
33503 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33505 window.location.href = this.href;
33508 //selection on single brick only
33509 selectBrick : function() {
33511 if (!this.parentId) {
33515 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33516 var index = m.selectedBrick.indexOf(this.id);
33519 m.selectedBrick.splice(index,1);
33520 this.el.removeClass(this.activeClass);
33524 for(var i = 0; i < m.selectedBrick.length; i++) {
33525 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33526 b.el.removeClass(b.activeClass);
33529 m.selectedBrick = [];
33531 m.selectedBrick.push(this.id);
33532 this.el.addClass(this.activeClass);
33536 isSelected : function(){
33537 return this.el.hasClass(this.activeClass);
33542 Roo.apply(Roo.bootstrap.MasonryBrick, {
33545 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33547 * register a Masonry Brick
33548 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33551 register : function(brick)
33553 //this.groups[brick.id] = brick;
33554 this.groups.add(brick.id, brick);
33557 * fetch a masonry brick based on the masonry brick ID
33558 * @param {string} the masonry brick to add
33559 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33562 get: function(brick_id)
33564 // if (typeof(this.groups[brick_id]) == 'undefined') {
33567 // return this.groups[brick_id] ;
33569 if(this.groups.key(brick_id)) {
33570 return this.groups.key(brick_id);
33588 * @class Roo.bootstrap.Brick
33589 * @extends Roo.bootstrap.Component
33590 * Bootstrap Brick class
33593 * Create a new Brick
33594 * @param {Object} config The config object
33597 Roo.bootstrap.Brick = function(config){
33598 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33604 * When a Brick is click
33605 * @param {Roo.bootstrap.Brick} this
33606 * @param {Roo.EventObject} e
33612 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33615 * @cfg {String} title
33619 * @cfg {String} html
33623 * @cfg {String} bgimage
33627 * @cfg {String} cls
33631 * @cfg {String} href
33635 * @cfg {String} video
33639 * @cfg {Boolean} square
33643 getAutoCreate : function()
33645 var cls = 'roo-brick';
33647 if(this.href.length){
33648 cls += ' roo-brick-link';
33651 if(this.bgimage.length){
33652 cls += ' roo-brick-image';
33655 if(!this.html.length && !this.bgimage.length){
33656 cls += ' roo-brick-center-title';
33659 if(!this.html.length && this.bgimage.length){
33660 cls += ' roo-brick-bottom-title';
33664 cls += ' ' + this.cls;
33668 tag: (this.href.length) ? 'a' : 'div',
33673 cls: 'roo-brick-paragraph',
33679 if(this.href.length){
33680 cfg.href = this.href;
33683 var cn = cfg.cn[0].cn;
33685 if(this.title.length){
33688 cls: 'roo-brick-title',
33693 if(this.html.length){
33696 cls: 'roo-brick-text',
33703 if(this.bgimage.length){
33706 cls: 'roo-brick-image-view',
33714 initEvents: function()
33716 if(this.title.length || this.html.length){
33717 this.el.on('mouseenter' ,this.enter, this);
33718 this.el.on('mouseleave', this.leave, this);
33721 Roo.EventManager.onWindowResize(this.resize, this);
33723 if(this.bgimage.length){
33724 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33725 this.imageEl.on('load', this.onImageLoad, this);
33732 onImageLoad : function()
33737 resize : function()
33739 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33741 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33743 if(this.bgimage.length){
33744 var image = this.el.select('.roo-brick-image-view', true).first();
33746 image.setWidth(paragraph.getWidth());
33749 image.setHeight(paragraph.getWidth());
33752 this.el.setHeight(image.getHeight());
33753 paragraph.setHeight(image.getHeight());
33759 enter: function(e, el)
33761 e.preventDefault();
33763 if(this.bgimage.length){
33764 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33765 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33769 leave: function(e, el)
33771 e.preventDefault();
33773 if(this.bgimage.length){
33774 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33775 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33790 * @class Roo.bootstrap.NumberField
33791 * @extends Roo.bootstrap.Input
33792 * Bootstrap NumberField class
33798 * Create a new NumberField
33799 * @param {Object} config The config object
33802 Roo.bootstrap.NumberField = function(config){
33803 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33806 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33809 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33811 allowDecimals : true,
33813 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33815 decimalSeparator : ".",
33817 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33819 decimalPrecision : 2,
33821 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33823 allowNegative : true,
33826 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33830 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33832 minValue : Number.NEGATIVE_INFINITY,
33834 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33836 maxValue : Number.MAX_VALUE,
33838 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33840 minText : "The minimum value for this field is {0}",
33842 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33844 maxText : "The maximum value for this field is {0}",
33846 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33847 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33849 nanText : "{0} is not a valid number",
33851 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33853 thousandsDelimiter : false,
33855 * @cfg {String} valueAlign alignment of value
33857 valueAlign : "left",
33859 getAutoCreate : function()
33861 var hiddenInput = {
33865 cls: 'hidden-number-input'
33869 hiddenInput.name = this.name;
33874 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33876 this.name = hiddenInput.name;
33878 if(cfg.cn.length > 0) {
33879 cfg.cn.push(hiddenInput);
33886 initEvents : function()
33888 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33890 var allowed = "0123456789";
33892 if(this.allowDecimals){
33893 allowed += this.decimalSeparator;
33896 if(this.allowNegative){
33900 if(this.thousandsDelimiter) {
33904 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33906 var keyPress = function(e){
33908 var k = e.getKey();
33910 var c = e.getCharCode();
33913 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33914 allowed.indexOf(String.fromCharCode(c)) === -1
33920 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33924 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33929 this.el.on("keypress", keyPress, this);
33932 validateValue : function(value)
33935 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33939 var num = this.parseValue(value);
33942 this.markInvalid(String.format(this.nanText, value));
33946 if(num < this.minValue){
33947 this.markInvalid(String.format(this.minText, this.minValue));
33951 if(num > this.maxValue){
33952 this.markInvalid(String.format(this.maxText, this.maxValue));
33959 getValue : function()
33961 var v = this.hiddenEl().getValue();
33963 return this.fixPrecision(this.parseValue(v));
33966 parseValue : function(value)
33968 if(this.thousandsDelimiter) {
33970 r = new RegExp(",", "g");
33971 value = value.replace(r, "");
33974 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33975 return isNaN(value) ? '' : value;
33978 fixPrecision : function(value)
33980 if(this.thousandsDelimiter) {
33982 r = new RegExp(",", "g");
33983 value = value.replace(r, "");
33986 var nan = isNaN(value);
33988 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33989 return nan ? '' : value;
33991 return parseFloat(value).toFixed(this.decimalPrecision);
33994 setValue : function(v)
33996 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
34002 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
34004 this.inputEl().dom.value = (v == '') ? '' :
34005 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
34007 if(!this.allowZero && v === '0') {
34008 this.hiddenEl().dom.value = '';
34009 this.inputEl().dom.value = '';
34016 decimalPrecisionFcn : function(v)
34018 return Math.floor(v);
34021 beforeBlur : function()
34023 var v = this.parseValue(this.getRawValue());
34025 if(v || v === 0 || v === ''){
34030 hiddenEl : function()
34032 return this.el.select('input.hidden-number-input',true).first();
34044 * @class Roo.bootstrap.DocumentSlider
34045 * @extends Roo.bootstrap.Component
34046 * Bootstrap DocumentSlider class
34049 * Create a new DocumentViewer
34050 * @param {Object} config The config object
34053 Roo.bootstrap.DocumentSlider = function(config){
34054 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34061 * Fire after initEvent
34062 * @param {Roo.bootstrap.DocumentSlider} this
34067 * Fire after update
34068 * @param {Roo.bootstrap.DocumentSlider} this
34074 * @param {Roo.bootstrap.DocumentSlider} this
34080 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34086 getAutoCreate : function()
34090 cls : 'roo-document-slider',
34094 cls : 'roo-document-slider-header',
34098 cls : 'roo-document-slider-header-title'
34104 cls : 'roo-document-slider-body',
34108 cls : 'roo-document-slider-prev',
34112 cls : 'fa fa-chevron-left'
34118 cls : 'roo-document-slider-thumb',
34122 cls : 'roo-document-slider-image'
34128 cls : 'roo-document-slider-next',
34132 cls : 'fa fa-chevron-right'
34144 initEvents : function()
34146 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34147 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34149 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34150 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34152 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34153 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34155 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34156 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34158 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34159 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34161 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34162 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34164 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34165 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34167 this.thumbEl.on('click', this.onClick, this);
34169 this.prevIndicator.on('click', this.prev, this);
34171 this.nextIndicator.on('click', this.next, this);
34175 initial : function()
34177 if(this.files.length){
34178 this.indicator = 1;
34182 this.fireEvent('initial', this);
34185 update : function()
34187 this.imageEl.attr('src', this.files[this.indicator - 1]);
34189 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34191 this.prevIndicator.show();
34193 if(this.indicator == 1){
34194 this.prevIndicator.hide();
34197 this.nextIndicator.show();
34199 if(this.indicator == this.files.length){
34200 this.nextIndicator.hide();
34203 this.thumbEl.scrollTo('top');
34205 this.fireEvent('update', this);
34208 onClick : function(e)
34210 e.preventDefault();
34212 this.fireEvent('click', this);
34217 e.preventDefault();
34219 this.indicator = Math.max(1, this.indicator - 1);
34226 e.preventDefault();
34228 this.indicator = Math.min(this.files.length, this.indicator + 1);
34242 * @class Roo.bootstrap.RadioSet
34243 * @extends Roo.bootstrap.Input
34244 * Bootstrap RadioSet class
34245 * @cfg {String} indicatorpos (left|right) default left
34246 * @cfg {Boolean} inline (true|false) inline the element (default true)
34247 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34249 * Create a new RadioSet
34250 * @param {Object} config The config object
34253 Roo.bootstrap.RadioSet = function(config){
34255 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34259 Roo.bootstrap.RadioSet.register(this);
34264 * Fires when the element is checked or unchecked.
34265 * @param {Roo.bootstrap.RadioSet} this This radio
34266 * @param {Roo.bootstrap.Radio} item The checked item
34271 * Fires when the element is click.
34272 * @param {Roo.bootstrap.RadioSet} this This radio set
34273 * @param {Roo.bootstrap.Radio} item The checked item
34274 * @param {Roo.EventObject} e The event object
34281 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34289 indicatorpos : 'left',
34291 getAutoCreate : function()
34295 cls : 'roo-radio-set-label',
34299 html : this.fieldLabel
34303 if (Roo.bootstrap.version == 3) {
34306 if(this.indicatorpos == 'left'){
34309 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34310 tooltip : 'This field is required'
34315 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34316 tooltip : 'This field is required'
34322 cls : 'roo-radio-set-items'
34325 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34327 if (align === 'left' && this.fieldLabel.length) {
34330 cls : "roo-radio-set-right",
34336 if(this.labelWidth > 12){
34337 label.style = "width: " + this.labelWidth + 'px';
34340 if(this.labelWidth < 13 && this.labelmd == 0){
34341 this.labelmd = this.labelWidth;
34344 if(this.labellg > 0){
34345 label.cls += ' col-lg-' + this.labellg;
34346 items.cls += ' col-lg-' + (12 - this.labellg);
34349 if(this.labelmd > 0){
34350 label.cls += ' col-md-' + this.labelmd;
34351 items.cls += ' col-md-' + (12 - this.labelmd);
34354 if(this.labelsm > 0){
34355 label.cls += ' col-sm-' + this.labelsm;
34356 items.cls += ' col-sm-' + (12 - this.labelsm);
34359 if(this.labelxs > 0){
34360 label.cls += ' col-xs-' + this.labelxs;
34361 items.cls += ' col-xs-' + (12 - this.labelxs);
34367 cls : 'roo-radio-set',
34371 cls : 'roo-radio-set-input',
34374 value : this.value ? this.value : ''
34381 if(this.weight.length){
34382 cfg.cls += ' roo-radio-' + this.weight;
34386 cfg.cls += ' roo-radio-set-inline';
34390 ['xs','sm','md','lg'].map(function(size){
34391 if (settings[size]) {
34392 cfg.cls += ' col-' + size + '-' + settings[size];
34400 initEvents : function()
34402 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34403 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34405 if(!this.fieldLabel.length){
34406 this.labelEl.hide();
34409 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34410 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34412 this.indicator = this.indicatorEl();
34414 if(this.indicator){
34415 this.indicator.addClass('invisible');
34418 this.originalValue = this.getValue();
34422 inputEl: function ()
34424 return this.el.select('.roo-radio-set-input', true).first();
34427 getChildContainer : function()
34429 return this.itemsEl;
34432 register : function(item)
34434 this.radioes.push(item);
34438 validate : function()
34440 if(this.getVisibilityEl().hasClass('hidden')){
34446 Roo.each(this.radioes, function(i){
34455 if(this.allowBlank) {
34459 if(this.disabled || valid){
34464 this.markInvalid();
34469 markValid : function()
34471 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34472 this.indicatorEl().removeClass('visible');
34473 this.indicatorEl().addClass('invisible');
34477 if (Roo.bootstrap.version == 3) {
34478 this.el.removeClass([this.invalidClass, this.validClass]);
34479 this.el.addClass(this.validClass);
34481 this.el.removeClass(['is-invalid','is-valid']);
34482 this.el.addClass(['is-valid']);
34484 this.fireEvent('valid', this);
34487 markInvalid : function(msg)
34489 if(this.allowBlank || this.disabled){
34493 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34494 this.indicatorEl().removeClass('invisible');
34495 this.indicatorEl().addClass('visible');
34497 if (Roo.bootstrap.version == 3) {
34498 this.el.removeClass([this.invalidClass, this.validClass]);
34499 this.el.addClass(this.invalidClass);
34501 this.el.removeClass(['is-invalid','is-valid']);
34502 this.el.addClass(['is-invalid']);
34505 this.fireEvent('invalid', this, msg);
34509 setValue : function(v, suppressEvent)
34511 if(this.value === v){
34518 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34521 Roo.each(this.radioes, function(i){
34523 i.el.removeClass('checked');
34526 Roo.each(this.radioes, function(i){
34528 if(i.value === v || i.value.toString() === v.toString()){
34530 i.el.addClass('checked');
34532 if(suppressEvent !== true){
34533 this.fireEvent('check', this, i);
34544 clearInvalid : function(){
34546 if(!this.el || this.preventMark){
34550 this.el.removeClass([this.invalidClass]);
34552 this.fireEvent('valid', this);
34557 Roo.apply(Roo.bootstrap.RadioSet, {
34561 register : function(set)
34563 this.groups[set.name] = set;
34566 get: function(name)
34568 if (typeof(this.groups[name]) == 'undefined') {
34572 return this.groups[name] ;
34578 * Ext JS Library 1.1.1
34579 * Copyright(c) 2006-2007, Ext JS, LLC.
34581 * Originally Released Under LGPL - original licence link has changed is not relivant.
34584 * <script type="text/javascript">
34589 * @class Roo.bootstrap.SplitBar
34590 * @extends Roo.util.Observable
34591 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34595 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34596 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34597 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34598 split.minSize = 100;
34599 split.maxSize = 600;
34600 split.animate = true;
34601 split.on('moved', splitterMoved);
34604 * Create a new SplitBar
34605 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34606 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34607 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34608 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34609 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34610 position of the SplitBar).
34612 Roo.bootstrap.SplitBar = function(cfg){
34617 // dragElement : elm
34618 // resizingElement: el,
34620 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34621 // placement : Roo.bootstrap.SplitBar.LEFT ,
34622 // existingProxy ???
34625 this.el = Roo.get(cfg.dragElement, true);
34626 this.el.dom.unselectable = "on";
34628 this.resizingEl = Roo.get(cfg.resizingElement, true);
34632 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34633 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34636 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34639 * The minimum size of the resizing element. (Defaults to 0)
34645 * The maximum size of the resizing element. (Defaults to 2000)
34648 this.maxSize = 2000;
34651 * Whether to animate the transition to the new size
34654 this.animate = false;
34657 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34660 this.useShim = false;
34665 if(!cfg.existingProxy){
34667 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34669 this.proxy = Roo.get(cfg.existingProxy).dom;
34672 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34675 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34678 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34681 this.dragSpecs = {};
34684 * @private The adapter to use to positon and resize elements
34686 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34687 this.adapter.init(this);
34689 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34691 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34692 this.el.addClass("roo-splitbar-h");
34695 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34696 this.el.addClass("roo-splitbar-v");
34702 * Fires when the splitter is moved (alias for {@link #event-moved})
34703 * @param {Roo.bootstrap.SplitBar} this
34704 * @param {Number} newSize the new width or height
34709 * Fires when the splitter is moved
34710 * @param {Roo.bootstrap.SplitBar} this
34711 * @param {Number} newSize the new width or height
34715 * @event beforeresize
34716 * Fires before the splitter is dragged
34717 * @param {Roo.bootstrap.SplitBar} this
34719 "beforeresize" : true,
34721 "beforeapply" : true
34724 Roo.util.Observable.call(this);
34727 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34728 onStartProxyDrag : function(x, y){
34729 this.fireEvent("beforeresize", this);
34731 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34733 o.enableDisplayMode("block");
34734 // all splitbars share the same overlay
34735 Roo.bootstrap.SplitBar.prototype.overlay = o;
34737 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34738 this.overlay.show();
34739 Roo.get(this.proxy).setDisplayed("block");
34740 var size = this.adapter.getElementSize(this);
34741 this.activeMinSize = this.getMinimumSize();;
34742 this.activeMaxSize = this.getMaximumSize();;
34743 var c1 = size - this.activeMinSize;
34744 var c2 = Math.max(this.activeMaxSize - size, 0);
34745 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34746 this.dd.resetConstraints();
34747 this.dd.setXConstraint(
34748 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34749 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34751 this.dd.setYConstraint(0, 0);
34753 this.dd.resetConstraints();
34754 this.dd.setXConstraint(0, 0);
34755 this.dd.setYConstraint(
34756 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34757 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34760 this.dragSpecs.startSize = size;
34761 this.dragSpecs.startPoint = [x, y];
34762 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34766 * @private Called after the drag operation by the DDProxy
34768 onEndProxyDrag : function(e){
34769 Roo.get(this.proxy).setDisplayed(false);
34770 var endPoint = Roo.lib.Event.getXY(e);
34772 this.overlay.hide();
34775 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34776 newSize = this.dragSpecs.startSize +
34777 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34778 endPoint[0] - this.dragSpecs.startPoint[0] :
34779 this.dragSpecs.startPoint[0] - endPoint[0]
34782 newSize = this.dragSpecs.startSize +
34783 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34784 endPoint[1] - this.dragSpecs.startPoint[1] :
34785 this.dragSpecs.startPoint[1] - endPoint[1]
34788 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34789 if(newSize != this.dragSpecs.startSize){
34790 if(this.fireEvent('beforeapply', this, newSize) !== false){
34791 this.adapter.setElementSize(this, newSize);
34792 this.fireEvent("moved", this, newSize);
34793 this.fireEvent("resize", this, newSize);
34799 * Get the adapter this SplitBar uses
34800 * @return The adapter object
34802 getAdapter : function(){
34803 return this.adapter;
34807 * Set the adapter this SplitBar uses
34808 * @param {Object} adapter A SplitBar adapter object
34810 setAdapter : function(adapter){
34811 this.adapter = adapter;
34812 this.adapter.init(this);
34816 * Gets the minimum size for the resizing element
34817 * @return {Number} The minimum size
34819 getMinimumSize : function(){
34820 return this.minSize;
34824 * Sets the minimum size for the resizing element
34825 * @param {Number} minSize The minimum size
34827 setMinimumSize : function(minSize){
34828 this.minSize = minSize;
34832 * Gets the maximum size for the resizing element
34833 * @return {Number} The maximum size
34835 getMaximumSize : function(){
34836 return this.maxSize;
34840 * Sets the maximum size for the resizing element
34841 * @param {Number} maxSize The maximum size
34843 setMaximumSize : function(maxSize){
34844 this.maxSize = maxSize;
34848 * Sets the initialize size for the resizing element
34849 * @param {Number} size The initial size
34851 setCurrentSize : function(size){
34852 var oldAnimate = this.animate;
34853 this.animate = false;
34854 this.adapter.setElementSize(this, size);
34855 this.animate = oldAnimate;
34859 * Destroy this splitbar.
34860 * @param {Boolean} removeEl True to remove the element
34862 destroy : function(removeEl){
34864 this.shim.remove();
34867 this.proxy.parentNode.removeChild(this.proxy);
34875 * @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.
34877 Roo.bootstrap.SplitBar.createProxy = function(dir){
34878 var proxy = new Roo.Element(document.createElement("div"));
34879 proxy.unselectable();
34880 var cls = 'roo-splitbar-proxy';
34881 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34882 document.body.appendChild(proxy.dom);
34887 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34888 * Default Adapter. It assumes the splitter and resizing element are not positioned
34889 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34891 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34894 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34895 // do nothing for now
34896 init : function(s){
34900 * Called before drag operations to get the current size of the resizing element.
34901 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34903 getElementSize : function(s){
34904 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34905 return s.resizingEl.getWidth();
34907 return s.resizingEl.getHeight();
34912 * Called after drag operations to set the size of the resizing element.
34913 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34914 * @param {Number} newSize The new size to set
34915 * @param {Function} onComplete A function to be invoked when resizing is complete
34917 setElementSize : function(s, newSize, onComplete){
34918 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34920 s.resizingEl.setWidth(newSize);
34922 onComplete(s, newSize);
34925 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34930 s.resizingEl.setHeight(newSize);
34932 onComplete(s, newSize);
34935 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34942 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34943 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34944 * Adapter that moves the splitter element to align with the resized sizing element.
34945 * Used with an absolute positioned SplitBar.
34946 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34947 * document.body, make sure you assign an id to the body element.
34949 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34950 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34951 this.container = Roo.get(container);
34954 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34955 init : function(s){
34956 this.basic.init(s);
34959 getElementSize : function(s){
34960 return this.basic.getElementSize(s);
34963 setElementSize : function(s, newSize, onComplete){
34964 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34967 moveSplitter : function(s){
34968 var yes = Roo.bootstrap.SplitBar;
34969 switch(s.placement){
34971 s.el.setX(s.resizingEl.getRight());
34974 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34977 s.el.setY(s.resizingEl.getBottom());
34980 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34987 * Orientation constant - Create a vertical SplitBar
34991 Roo.bootstrap.SplitBar.VERTICAL = 1;
34994 * Orientation constant - Create a horizontal SplitBar
34998 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
35001 * Placement constant - The resizing element is to the left of the splitter element
35005 Roo.bootstrap.SplitBar.LEFT = 1;
35008 * Placement constant - The resizing element is to the right of the splitter element
35012 Roo.bootstrap.SplitBar.RIGHT = 2;
35015 * Placement constant - The resizing element is positioned above the splitter element
35019 Roo.bootstrap.SplitBar.TOP = 3;
35022 * Placement constant - The resizing element is positioned under splitter element
35026 Roo.bootstrap.SplitBar.BOTTOM = 4;
35027 Roo.namespace("Roo.bootstrap.layout");/*
35029 * Ext JS Library 1.1.1
35030 * Copyright(c) 2006-2007, Ext JS, LLC.
35032 * Originally Released Under LGPL - original licence link has changed is not relivant.
35035 * <script type="text/javascript">
35039 * @class Roo.bootstrap.layout.Manager
35040 * @extends Roo.bootstrap.Component
35041 * Base class for layout managers.
35043 Roo.bootstrap.layout.Manager = function(config)
35045 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
35051 /** false to disable window resize monitoring @type Boolean */
35052 this.monitorWindowResize = true;
35057 * Fires when a layout is performed.
35058 * @param {Roo.LayoutManager} this
35062 * @event regionresized
35063 * Fires when the user resizes a region.
35064 * @param {Roo.LayoutRegion} region The resized region
35065 * @param {Number} newSize The new size (width for east/west, height for north/south)
35067 "regionresized" : true,
35069 * @event regioncollapsed
35070 * Fires when a region is collapsed.
35071 * @param {Roo.LayoutRegion} region The collapsed region
35073 "regioncollapsed" : true,
35075 * @event regionexpanded
35076 * Fires when a region is expanded.
35077 * @param {Roo.LayoutRegion} region The expanded region
35079 "regionexpanded" : true
35081 this.updating = false;
35084 this.el = Roo.get(config.el);
35090 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35095 monitorWindowResize : true,
35101 onRender : function(ct, position)
35104 this.el = Roo.get(ct);
35107 //this.fireEvent('render',this);
35111 initEvents: function()
35115 // ie scrollbar fix
35116 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35117 document.body.scroll = "no";
35118 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35119 this.el.position('relative');
35121 this.id = this.el.id;
35122 this.el.addClass("roo-layout-container");
35123 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35124 if(this.el.dom != document.body ) {
35125 this.el.on('resize', this.layout,this);
35126 this.el.on('show', this.layout,this);
35132 * Returns true if this layout is currently being updated
35133 * @return {Boolean}
35135 isUpdating : function(){
35136 return this.updating;
35140 * Suspend the LayoutManager from doing auto-layouts while
35141 * making multiple add or remove calls
35143 beginUpdate : function(){
35144 this.updating = true;
35148 * Restore auto-layouts and optionally disable the manager from performing a layout
35149 * @param {Boolean} noLayout true to disable a layout update
35151 endUpdate : function(noLayout){
35152 this.updating = false;
35158 layout: function(){
35162 onRegionResized : function(region, newSize){
35163 this.fireEvent("regionresized", region, newSize);
35167 onRegionCollapsed : function(region){
35168 this.fireEvent("regioncollapsed", region);
35171 onRegionExpanded : function(region){
35172 this.fireEvent("regionexpanded", region);
35176 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35177 * performs box-model adjustments.
35178 * @return {Object} The size as an object {width: (the width), height: (the height)}
35180 getViewSize : function()
35183 if(this.el.dom != document.body){
35184 size = this.el.getSize();
35186 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35188 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35189 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35194 * Returns the Element this layout is bound to.
35195 * @return {Roo.Element}
35197 getEl : function(){
35202 * Returns the specified region.
35203 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35204 * @return {Roo.LayoutRegion}
35206 getRegion : function(target){
35207 return this.regions[target.toLowerCase()];
35210 onWindowResize : function(){
35211 if(this.monitorWindowResize){
35218 * Ext JS Library 1.1.1
35219 * Copyright(c) 2006-2007, Ext JS, LLC.
35221 * Originally Released Under LGPL - original licence link has changed is not relivant.
35224 * <script type="text/javascript">
35227 * @class Roo.bootstrap.layout.Border
35228 * @extends Roo.bootstrap.layout.Manager
35229 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35230 * please see: examples/bootstrap/nested.html<br><br>
35232 <b>The container the layout is rendered into can be either the body element or any other element.
35233 If it is not the body element, the container needs to either be an absolute positioned element,
35234 or you will need to add "position:relative" to the css of the container. You will also need to specify
35235 the container size if it is not the body element.</b>
35238 * Create a new Border
35239 * @param {Object} config Configuration options
35241 Roo.bootstrap.layout.Border = function(config){
35242 config = config || {};
35243 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35247 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35248 if(config[region]){
35249 config[region].region = region;
35250 this.addRegion(config[region]);
35256 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35258 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35260 parent : false, // this might point to a 'nest' or a ???
35263 * Creates and adds a new region if it doesn't already exist.
35264 * @param {String} target The target region key (north, south, east, west or center).
35265 * @param {Object} config The regions config object
35266 * @return {BorderLayoutRegion} The new region
35268 addRegion : function(config)
35270 if(!this.regions[config.region]){
35271 var r = this.factory(config);
35272 this.bindRegion(r);
35274 return this.regions[config.region];
35278 bindRegion : function(r){
35279 this.regions[r.config.region] = r;
35281 r.on("visibilitychange", this.layout, this);
35282 r.on("paneladded", this.layout, this);
35283 r.on("panelremoved", this.layout, this);
35284 r.on("invalidated", this.layout, this);
35285 r.on("resized", this.onRegionResized, this);
35286 r.on("collapsed", this.onRegionCollapsed, this);
35287 r.on("expanded", this.onRegionExpanded, this);
35291 * Performs a layout update.
35293 layout : function()
35295 if(this.updating) {
35299 // render all the rebions if they have not been done alreayd?
35300 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35301 if(this.regions[region] && !this.regions[region].bodyEl){
35302 this.regions[region].onRender(this.el)
35306 var size = this.getViewSize();
35307 var w = size.width;
35308 var h = size.height;
35313 //var x = 0, y = 0;
35315 var rs = this.regions;
35316 var north = rs["north"];
35317 var south = rs["south"];
35318 var west = rs["west"];
35319 var east = rs["east"];
35320 var center = rs["center"];
35321 //if(this.hideOnLayout){ // not supported anymore
35322 //c.el.setStyle("display", "none");
35324 if(north && north.isVisible()){
35325 var b = north.getBox();
35326 var m = north.getMargins();
35327 b.width = w - (m.left+m.right);
35330 centerY = b.height + b.y + m.bottom;
35331 centerH -= centerY;
35332 north.updateBox(this.safeBox(b));
35334 if(south && south.isVisible()){
35335 var b = south.getBox();
35336 var m = south.getMargins();
35337 b.width = w - (m.left+m.right);
35339 var totalHeight = (b.height + m.top + m.bottom);
35340 b.y = h - totalHeight + m.top;
35341 centerH -= totalHeight;
35342 south.updateBox(this.safeBox(b));
35344 if(west && west.isVisible()){
35345 var b = west.getBox();
35346 var m = west.getMargins();
35347 b.height = centerH - (m.top+m.bottom);
35349 b.y = centerY + m.top;
35350 var totalWidth = (b.width + m.left + m.right);
35351 centerX += totalWidth;
35352 centerW -= totalWidth;
35353 west.updateBox(this.safeBox(b));
35355 if(east && east.isVisible()){
35356 var b = east.getBox();
35357 var m = east.getMargins();
35358 b.height = centerH - (m.top+m.bottom);
35359 var totalWidth = (b.width + m.left + m.right);
35360 b.x = w - totalWidth + m.left;
35361 b.y = centerY + m.top;
35362 centerW -= totalWidth;
35363 east.updateBox(this.safeBox(b));
35366 var m = center.getMargins();
35368 x: centerX + m.left,
35369 y: centerY + m.top,
35370 width: centerW - (m.left+m.right),
35371 height: centerH - (m.top+m.bottom)
35373 //if(this.hideOnLayout){
35374 //center.el.setStyle("display", "block");
35376 center.updateBox(this.safeBox(centerBox));
35379 this.fireEvent("layout", this);
35383 safeBox : function(box){
35384 box.width = Math.max(0, box.width);
35385 box.height = Math.max(0, box.height);
35390 * Adds a ContentPanel (or subclass) to this layout.
35391 * @param {String} target The target region key (north, south, east, west or center).
35392 * @param {Roo.ContentPanel} panel The panel to add
35393 * @return {Roo.ContentPanel} The added panel
35395 add : function(target, panel){
35397 target = target.toLowerCase();
35398 return this.regions[target].add(panel);
35402 * Remove a ContentPanel (or subclass) to this layout.
35403 * @param {String} target The target region key (north, south, east, west or center).
35404 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35405 * @return {Roo.ContentPanel} The removed panel
35407 remove : function(target, panel){
35408 target = target.toLowerCase();
35409 return this.regions[target].remove(panel);
35413 * Searches all regions for a panel with the specified id
35414 * @param {String} panelId
35415 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35417 findPanel : function(panelId){
35418 var rs = this.regions;
35419 for(var target in rs){
35420 if(typeof rs[target] != "function"){
35421 var p = rs[target].getPanel(panelId);
35431 * Searches all regions for a panel with the specified id and activates (shows) it.
35432 * @param {String/ContentPanel} panelId The panels id or the panel itself
35433 * @return {Roo.ContentPanel} The shown panel or null
35435 showPanel : function(panelId) {
35436 var rs = this.regions;
35437 for(var target in rs){
35438 var r = rs[target];
35439 if(typeof r != "function"){
35440 if(r.hasPanel(panelId)){
35441 return r.showPanel(panelId);
35449 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35450 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35453 restoreState : function(provider){
35455 provider = Roo.state.Manager;
35457 var sm = new Roo.LayoutStateManager();
35458 sm.init(this, provider);
35464 * Adds a xtype elements to the layout.
35468 xtype : 'ContentPanel',
35475 xtype : 'NestedLayoutPanel',
35481 items : [ ... list of content panels or nested layout panels.. ]
35485 * @param {Object} cfg Xtype definition of item to add.
35487 addxtype : function(cfg)
35489 // basically accepts a pannel...
35490 // can accept a layout region..!?!?
35491 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35494 // theory? children can only be panels??
35496 //if (!cfg.xtype.match(/Panel$/)) {
35501 if (typeof(cfg.region) == 'undefined') {
35502 Roo.log("Failed to add Panel, region was not set");
35506 var region = cfg.region;
35512 xitems = cfg.items;
35517 if ( region == 'center') {
35518 Roo.log("Center: " + cfg.title);
35524 case 'Content': // ContentPanel (el, cfg)
35525 case 'Scroll': // ContentPanel (el, cfg)
35527 cfg.autoCreate = cfg.autoCreate || true;
35528 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35530 // var el = this.el.createChild();
35531 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35534 this.add(region, ret);
35538 case 'TreePanel': // our new panel!
35539 cfg.el = this.el.createChild();
35540 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35541 this.add(region, ret);
35546 // create a new Layout (which is a Border Layout...
35548 var clayout = cfg.layout;
35549 clayout.el = this.el.createChild();
35550 clayout.items = clayout.items || [];
35554 // replace this exitems with the clayout ones..
35555 xitems = clayout.items;
35557 // force background off if it's in center...
35558 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35559 cfg.background = false;
35561 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35564 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35565 //console.log('adding nested layout panel ' + cfg.toSource());
35566 this.add(region, ret);
35567 nb = {}; /// find first...
35572 // needs grid and region
35574 //var el = this.getRegion(region).el.createChild();
35576 *var el = this.el.createChild();
35577 // create the grid first...
35578 cfg.grid.container = el;
35579 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35582 if (region == 'center' && this.active ) {
35583 cfg.background = false;
35586 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35588 this.add(region, ret);
35590 if (cfg.background) {
35591 // render grid on panel activation (if panel background)
35592 ret.on('activate', function(gp) {
35593 if (!gp.grid.rendered) {
35594 // gp.grid.render(el);
35598 // cfg.grid.render(el);
35604 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35605 // it was the old xcomponent building that caused this before.
35606 // espeically if border is the top element in the tree.
35616 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35618 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35619 this.add(region, ret);
35623 throw "Can not add '" + cfg.xtype + "' to Border";
35629 this.beginUpdate();
35633 Roo.each(xitems, function(i) {
35634 region = nb && i.region ? i.region : false;
35636 var add = ret.addxtype(i);
35639 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35640 if (!i.background) {
35641 abn[region] = nb[region] ;
35648 // make the last non-background panel active..
35649 //if (nb) { Roo.log(abn); }
35652 for(var r in abn) {
35653 region = this.getRegion(r);
35655 // tried using nb[r], but it does not work..
35657 region.showPanel(abn[r]);
35668 factory : function(cfg)
35671 var validRegions = Roo.bootstrap.layout.Border.regions;
35673 var target = cfg.region;
35676 var r = Roo.bootstrap.layout;
35680 return new r.North(cfg);
35682 return new r.South(cfg);
35684 return new r.East(cfg);
35686 return new r.West(cfg);
35688 return new r.Center(cfg);
35690 throw 'Layout region "'+target+'" not supported.';
35697 * Ext JS Library 1.1.1
35698 * Copyright(c) 2006-2007, Ext JS, LLC.
35700 * Originally Released Under LGPL - original licence link has changed is not relivant.
35703 * <script type="text/javascript">
35707 * @class Roo.bootstrap.layout.Basic
35708 * @extends Roo.util.Observable
35709 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35710 * and does not have a titlebar, tabs or any other features. All it does is size and position
35711 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35712 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35713 * @cfg {string} region the region that it inhabits..
35714 * @cfg {bool} skipConfig skip config?
35718 Roo.bootstrap.layout.Basic = function(config){
35720 this.mgr = config.mgr;
35722 this.position = config.region;
35724 var skipConfig = config.skipConfig;
35728 * @scope Roo.BasicLayoutRegion
35732 * @event beforeremove
35733 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35734 * @param {Roo.LayoutRegion} this
35735 * @param {Roo.ContentPanel} panel The panel
35736 * @param {Object} e The cancel event object
35738 "beforeremove" : true,
35740 * @event invalidated
35741 * Fires when the layout for this region is changed.
35742 * @param {Roo.LayoutRegion} this
35744 "invalidated" : true,
35746 * @event visibilitychange
35747 * Fires when this region is shown or hidden
35748 * @param {Roo.LayoutRegion} this
35749 * @param {Boolean} visibility true or false
35751 "visibilitychange" : true,
35753 * @event paneladded
35754 * Fires when a panel is added.
35755 * @param {Roo.LayoutRegion} this
35756 * @param {Roo.ContentPanel} panel The panel
35758 "paneladded" : true,
35760 * @event panelremoved
35761 * Fires when a panel is removed.
35762 * @param {Roo.LayoutRegion} this
35763 * @param {Roo.ContentPanel} panel The panel
35765 "panelremoved" : true,
35767 * @event beforecollapse
35768 * Fires when this region before collapse.
35769 * @param {Roo.LayoutRegion} this
35771 "beforecollapse" : true,
35774 * Fires when this region is collapsed.
35775 * @param {Roo.LayoutRegion} this
35777 "collapsed" : true,
35780 * Fires when this region is expanded.
35781 * @param {Roo.LayoutRegion} this
35786 * Fires when this region is slid into view.
35787 * @param {Roo.LayoutRegion} this
35789 "slideshow" : true,
35792 * Fires when this region slides out of view.
35793 * @param {Roo.LayoutRegion} this
35795 "slidehide" : true,
35797 * @event panelactivated
35798 * Fires when a panel is activated.
35799 * @param {Roo.LayoutRegion} this
35800 * @param {Roo.ContentPanel} panel The activated panel
35802 "panelactivated" : true,
35805 * Fires when the user resizes this region.
35806 * @param {Roo.LayoutRegion} this
35807 * @param {Number} newSize The new size (width for east/west, height for north/south)
35811 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35812 this.panels = new Roo.util.MixedCollection();
35813 this.panels.getKey = this.getPanelId.createDelegate(this);
35815 this.activePanel = null;
35816 // ensure listeners are added...
35818 if (config.listeners || config.events) {
35819 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35820 listeners : config.listeners || {},
35821 events : config.events || {}
35825 if(skipConfig !== true){
35826 this.applyConfig(config);
35830 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35832 getPanelId : function(p){
35836 applyConfig : function(config){
35837 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35838 this.config = config;
35843 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35844 * the width, for horizontal (north, south) the height.
35845 * @param {Number} newSize The new width or height
35847 resizeTo : function(newSize){
35848 var el = this.el ? this.el :
35849 (this.activePanel ? this.activePanel.getEl() : null);
35851 switch(this.position){
35854 el.setWidth(newSize);
35855 this.fireEvent("resized", this, newSize);
35859 el.setHeight(newSize);
35860 this.fireEvent("resized", this, newSize);
35866 getBox : function(){
35867 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35870 getMargins : function(){
35871 return this.margins;
35874 updateBox : function(box){
35876 var el = this.activePanel.getEl();
35877 el.dom.style.left = box.x + "px";
35878 el.dom.style.top = box.y + "px";
35879 this.activePanel.setSize(box.width, box.height);
35883 * Returns the container element for this region.
35884 * @return {Roo.Element}
35886 getEl : function(){
35887 return this.activePanel;
35891 * Returns true if this region is currently visible.
35892 * @return {Boolean}
35894 isVisible : function(){
35895 return this.activePanel ? true : false;
35898 setActivePanel : function(panel){
35899 panel = this.getPanel(panel);
35900 if(this.activePanel && this.activePanel != panel){
35901 this.activePanel.setActiveState(false);
35902 this.activePanel.getEl().setLeftTop(-10000,-10000);
35904 this.activePanel = panel;
35905 panel.setActiveState(true);
35907 panel.setSize(this.box.width, this.box.height);
35909 this.fireEvent("panelactivated", this, panel);
35910 this.fireEvent("invalidated");
35914 * Show the specified panel.
35915 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35916 * @return {Roo.ContentPanel} The shown panel or null
35918 showPanel : function(panel){
35919 panel = this.getPanel(panel);
35921 this.setActivePanel(panel);
35927 * Get the active panel for this region.
35928 * @return {Roo.ContentPanel} The active panel or null
35930 getActivePanel : function(){
35931 return this.activePanel;
35935 * Add the passed ContentPanel(s)
35936 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35937 * @return {Roo.ContentPanel} The panel added (if only one was added)
35939 add : function(panel){
35940 if(arguments.length > 1){
35941 for(var i = 0, len = arguments.length; i < len; i++) {
35942 this.add(arguments[i]);
35946 if(this.hasPanel(panel)){
35947 this.showPanel(panel);
35950 var el = panel.getEl();
35951 if(el.dom.parentNode != this.mgr.el.dom){
35952 this.mgr.el.dom.appendChild(el.dom);
35954 if(panel.setRegion){
35955 panel.setRegion(this);
35957 this.panels.add(panel);
35958 el.setStyle("position", "absolute");
35959 if(!panel.background){
35960 this.setActivePanel(panel);
35961 if(this.config.initialSize && this.panels.getCount()==1){
35962 this.resizeTo(this.config.initialSize);
35965 this.fireEvent("paneladded", this, panel);
35970 * Returns true if the panel is in this region.
35971 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35972 * @return {Boolean}
35974 hasPanel : function(panel){
35975 if(typeof panel == "object"){ // must be panel obj
35976 panel = panel.getId();
35978 return this.getPanel(panel) ? true : false;
35982 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35983 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35984 * @param {Boolean} preservePanel Overrides the config preservePanel option
35985 * @return {Roo.ContentPanel} The panel that was removed
35987 remove : function(panel, preservePanel){
35988 panel = this.getPanel(panel);
35993 this.fireEvent("beforeremove", this, panel, e);
35994 if(e.cancel === true){
35997 var panelId = panel.getId();
35998 this.panels.removeKey(panelId);
36003 * Returns the panel specified or null if it's not in this region.
36004 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36005 * @return {Roo.ContentPanel}
36007 getPanel : function(id){
36008 if(typeof id == "object"){ // must be panel obj
36011 return this.panels.get(id);
36015 * Returns this regions position (north/south/east/west/center).
36018 getPosition: function(){
36019 return this.position;
36023 * Ext JS Library 1.1.1
36024 * Copyright(c) 2006-2007, Ext JS, LLC.
36026 * Originally Released Under LGPL - original licence link has changed is not relivant.
36029 * <script type="text/javascript">
36033 * @class Roo.bootstrap.layout.Region
36034 * @extends Roo.bootstrap.layout.Basic
36035 * This class represents a region in a layout manager.
36037 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
36038 * @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})
36039 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
36040 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
36041 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
36042 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
36043 * @cfg {String} title The title for the region (overrides panel titles)
36044 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
36045 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
36046 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
36047 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
36048 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
36049 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
36050 * the space available, similar to FireFox 1.5 tabs (defaults to false)
36051 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
36052 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
36053 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
36055 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
36056 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36057 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36058 * @cfg {Number} width For East/West panels
36059 * @cfg {Number} height For North/South panels
36060 * @cfg {Boolean} split To show the splitter
36061 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36063 * @cfg {string} cls Extra CSS classes to add to region
36065 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36066 * @cfg {string} region the region that it inhabits..
36069 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36070 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36072 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36073 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36074 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36076 Roo.bootstrap.layout.Region = function(config)
36078 this.applyConfig(config);
36080 var mgr = config.mgr;
36081 var pos = config.region;
36082 config.skipConfig = true;
36083 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36086 this.onRender(mgr.el);
36089 this.visible = true;
36090 this.collapsed = false;
36091 this.unrendered_panels = [];
36094 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36096 position: '', // set by wrapper (eg. north/south etc..)
36097 unrendered_panels : null, // unrendered panels.
36099 tabPosition : false,
36101 mgr: false, // points to 'Border'
36104 createBody : function(){
36105 /** This region's body element
36106 * @type Roo.Element */
36107 this.bodyEl = this.el.createChild({
36109 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36113 onRender: function(ctr, pos)
36115 var dh = Roo.DomHelper;
36116 /** This region's container element
36117 * @type Roo.Element */
36118 this.el = dh.append(ctr.dom, {
36120 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36122 /** This region's title element
36123 * @type Roo.Element */
36125 this.titleEl = dh.append(this.el.dom, {
36127 unselectable: "on",
36128 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36130 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36131 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36135 this.titleEl.enableDisplayMode();
36136 /** This region's title text element
36137 * @type HTMLElement */
36138 this.titleTextEl = this.titleEl.dom.firstChild;
36139 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36141 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36142 this.closeBtn.enableDisplayMode();
36143 this.closeBtn.on("click", this.closeClicked, this);
36144 this.closeBtn.hide();
36146 this.createBody(this.config);
36147 if(this.config.hideWhenEmpty){
36149 this.on("paneladded", this.validateVisibility, this);
36150 this.on("panelremoved", this.validateVisibility, this);
36152 if(this.autoScroll){
36153 this.bodyEl.setStyle("overflow", "auto");
36155 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36157 //if(c.titlebar !== false){
36158 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36159 this.titleEl.hide();
36161 this.titleEl.show();
36162 if(this.config.title){
36163 this.titleTextEl.innerHTML = this.config.title;
36167 if(this.config.collapsed){
36168 this.collapse(true);
36170 if(this.config.hidden){
36174 if (this.unrendered_panels && this.unrendered_panels.length) {
36175 for (var i =0;i< this.unrendered_panels.length; i++) {
36176 this.add(this.unrendered_panels[i]);
36178 this.unrendered_panels = null;
36184 applyConfig : function(c)
36187 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36188 var dh = Roo.DomHelper;
36189 if(c.titlebar !== false){
36190 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36191 this.collapseBtn.on("click", this.collapse, this);
36192 this.collapseBtn.enableDisplayMode();
36194 if(c.showPin === true || this.showPin){
36195 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36196 this.stickBtn.enableDisplayMode();
36197 this.stickBtn.on("click", this.expand, this);
36198 this.stickBtn.hide();
36203 /** This region's collapsed element
36204 * @type Roo.Element */
36207 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36208 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36211 if(c.floatable !== false){
36212 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36213 this.collapsedEl.on("click", this.collapseClick, this);
36216 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36217 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36218 id: "message", unselectable: "on", style:{"float":"left"}});
36219 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36221 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36222 this.expandBtn.on("click", this.expand, this);
36226 if(this.collapseBtn){
36227 this.collapseBtn.setVisible(c.collapsible == true);
36230 this.cmargins = c.cmargins || this.cmargins ||
36231 (this.position == "west" || this.position == "east" ?
36232 {top: 0, left: 2, right:2, bottom: 0} :
36233 {top: 2, left: 0, right:0, bottom: 2});
36235 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36238 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36240 this.autoScroll = c.autoScroll || false;
36245 this.duration = c.duration || .30;
36246 this.slideDuration = c.slideDuration || .45;
36251 * Returns true if this region is currently visible.
36252 * @return {Boolean}
36254 isVisible : function(){
36255 return this.visible;
36259 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36260 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36262 //setCollapsedTitle : function(title){
36263 // title = title || " ";
36264 // if(this.collapsedTitleTextEl){
36265 // this.collapsedTitleTextEl.innerHTML = title;
36269 getBox : function(){
36271 // if(!this.collapsed){
36272 b = this.el.getBox(false, true);
36274 // b = this.collapsedEl.getBox(false, true);
36279 getMargins : function(){
36280 return this.margins;
36281 //return this.collapsed ? this.cmargins : this.margins;
36284 highlight : function(){
36285 this.el.addClass("x-layout-panel-dragover");
36288 unhighlight : function(){
36289 this.el.removeClass("x-layout-panel-dragover");
36292 updateBox : function(box)
36294 if (!this.bodyEl) {
36295 return; // not rendered yet..
36299 if(!this.collapsed){
36300 this.el.dom.style.left = box.x + "px";
36301 this.el.dom.style.top = box.y + "px";
36302 this.updateBody(box.width, box.height);
36304 this.collapsedEl.dom.style.left = box.x + "px";
36305 this.collapsedEl.dom.style.top = box.y + "px";
36306 this.collapsedEl.setSize(box.width, box.height);
36309 this.tabs.autoSizeTabs();
36313 updateBody : function(w, h)
36316 this.el.setWidth(w);
36317 w -= this.el.getBorderWidth("rl");
36318 if(this.config.adjustments){
36319 w += this.config.adjustments[0];
36322 if(h !== null && h > 0){
36323 this.el.setHeight(h);
36324 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36325 h -= this.el.getBorderWidth("tb");
36326 if(this.config.adjustments){
36327 h += this.config.adjustments[1];
36329 this.bodyEl.setHeight(h);
36331 h = this.tabs.syncHeight(h);
36334 if(this.panelSize){
36335 w = w !== null ? w : this.panelSize.width;
36336 h = h !== null ? h : this.panelSize.height;
36338 if(this.activePanel){
36339 var el = this.activePanel.getEl();
36340 w = w !== null ? w : el.getWidth();
36341 h = h !== null ? h : el.getHeight();
36342 this.panelSize = {width: w, height: h};
36343 this.activePanel.setSize(w, h);
36345 if(Roo.isIE && this.tabs){
36346 this.tabs.el.repaint();
36351 * Returns the container element for this region.
36352 * @return {Roo.Element}
36354 getEl : function(){
36359 * Hides this region.
36362 //if(!this.collapsed){
36363 this.el.dom.style.left = "-2000px";
36366 // this.collapsedEl.dom.style.left = "-2000px";
36367 // this.collapsedEl.hide();
36369 this.visible = false;
36370 this.fireEvent("visibilitychange", this, false);
36374 * Shows this region if it was previously hidden.
36377 //if(!this.collapsed){
36380 // this.collapsedEl.show();
36382 this.visible = true;
36383 this.fireEvent("visibilitychange", this, true);
36386 closeClicked : function(){
36387 if(this.activePanel){
36388 this.remove(this.activePanel);
36392 collapseClick : function(e){
36394 e.stopPropagation();
36397 e.stopPropagation();
36403 * Collapses this region.
36404 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36407 collapse : function(skipAnim, skipCheck = false){
36408 if(this.collapsed) {
36412 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36414 this.collapsed = true;
36416 this.split.el.hide();
36418 if(this.config.animate && skipAnim !== true){
36419 this.fireEvent("invalidated", this);
36420 this.animateCollapse();
36422 this.el.setLocation(-20000,-20000);
36424 this.collapsedEl.show();
36425 this.fireEvent("collapsed", this);
36426 this.fireEvent("invalidated", this);
36432 animateCollapse : function(){
36437 * Expands this region if it was previously collapsed.
36438 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36439 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36442 expand : function(e, skipAnim){
36444 e.stopPropagation();
36446 if(!this.collapsed || this.el.hasActiveFx()) {
36450 this.afterSlideIn();
36453 this.collapsed = false;
36454 if(this.config.animate && skipAnim !== true){
36455 this.animateExpand();
36459 this.split.el.show();
36461 this.collapsedEl.setLocation(-2000,-2000);
36462 this.collapsedEl.hide();
36463 this.fireEvent("invalidated", this);
36464 this.fireEvent("expanded", this);
36468 animateExpand : function(){
36472 initTabs : function()
36474 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36476 var ts = new Roo.bootstrap.panel.Tabs({
36477 el: this.bodyEl.dom,
36479 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36480 disableTooltips: this.config.disableTabTips,
36481 toolbar : this.config.toolbar
36484 if(this.config.hideTabs){
36485 ts.stripWrap.setDisplayed(false);
36488 ts.resizeTabs = this.config.resizeTabs === true;
36489 ts.minTabWidth = this.config.minTabWidth || 40;
36490 ts.maxTabWidth = this.config.maxTabWidth || 250;
36491 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36492 ts.monitorResize = false;
36493 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36494 ts.bodyEl.addClass('roo-layout-tabs-body');
36495 this.panels.each(this.initPanelAsTab, this);
36498 initPanelAsTab : function(panel){
36499 var ti = this.tabs.addTab(
36503 this.config.closeOnTab && panel.isClosable(),
36506 if(panel.tabTip !== undefined){
36507 ti.setTooltip(panel.tabTip);
36509 ti.on("activate", function(){
36510 this.setActivePanel(panel);
36513 if(this.config.closeOnTab){
36514 ti.on("beforeclose", function(t, e){
36516 this.remove(panel);
36520 panel.tabItem = ti;
36525 updatePanelTitle : function(panel, title)
36527 if(this.activePanel == panel){
36528 this.updateTitle(title);
36531 var ti = this.tabs.getTab(panel.getEl().id);
36533 if(panel.tabTip !== undefined){
36534 ti.setTooltip(panel.tabTip);
36539 updateTitle : function(title){
36540 if(this.titleTextEl && !this.config.title){
36541 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36545 setActivePanel : function(panel)
36547 panel = this.getPanel(panel);
36548 if(this.activePanel && this.activePanel != panel){
36549 if(this.activePanel.setActiveState(false) === false){
36553 this.activePanel = panel;
36554 panel.setActiveState(true);
36555 if(this.panelSize){
36556 panel.setSize(this.panelSize.width, this.panelSize.height);
36559 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36561 this.updateTitle(panel.getTitle());
36563 this.fireEvent("invalidated", this);
36565 this.fireEvent("panelactivated", this, panel);
36569 * Shows the specified panel.
36570 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36571 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36573 showPanel : function(panel)
36575 panel = this.getPanel(panel);
36578 var tab = this.tabs.getTab(panel.getEl().id);
36579 if(tab.isHidden()){
36580 this.tabs.unhideTab(tab.id);
36584 this.setActivePanel(panel);
36591 * Get the active panel for this region.
36592 * @return {Roo.ContentPanel} The active panel or null
36594 getActivePanel : function(){
36595 return this.activePanel;
36598 validateVisibility : function(){
36599 if(this.panels.getCount() < 1){
36600 this.updateTitle(" ");
36601 this.closeBtn.hide();
36604 if(!this.isVisible()){
36611 * Adds the passed ContentPanel(s) to this region.
36612 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36613 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36615 add : function(panel)
36617 if(arguments.length > 1){
36618 for(var i = 0, len = arguments.length; i < len; i++) {
36619 this.add(arguments[i]);
36624 // if we have not been rendered yet, then we can not really do much of this..
36625 if (!this.bodyEl) {
36626 this.unrendered_panels.push(panel);
36633 if(this.hasPanel(panel)){
36634 this.showPanel(panel);
36637 panel.setRegion(this);
36638 this.panels.add(panel);
36639 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36640 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36641 // and hide them... ???
36642 this.bodyEl.dom.appendChild(panel.getEl().dom);
36643 if(panel.background !== true){
36644 this.setActivePanel(panel);
36646 this.fireEvent("paneladded", this, panel);
36653 this.initPanelAsTab(panel);
36657 if(panel.background !== true){
36658 this.tabs.activate(panel.getEl().id);
36660 this.fireEvent("paneladded", this, panel);
36665 * Hides the tab for the specified panel.
36666 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36668 hidePanel : function(panel){
36669 if(this.tabs && (panel = this.getPanel(panel))){
36670 this.tabs.hideTab(panel.getEl().id);
36675 * Unhides the tab for a previously hidden panel.
36676 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36678 unhidePanel : function(panel){
36679 if(this.tabs && (panel = this.getPanel(panel))){
36680 this.tabs.unhideTab(panel.getEl().id);
36684 clearPanels : function(){
36685 while(this.panels.getCount() > 0){
36686 this.remove(this.panels.first());
36691 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36692 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36693 * @param {Boolean} preservePanel Overrides the config preservePanel option
36694 * @return {Roo.ContentPanel} The panel that was removed
36696 remove : function(panel, preservePanel)
36698 panel = this.getPanel(panel);
36703 this.fireEvent("beforeremove", this, panel, e);
36704 if(e.cancel === true){
36707 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36708 var panelId = panel.getId();
36709 this.panels.removeKey(panelId);
36711 document.body.appendChild(panel.getEl().dom);
36714 this.tabs.removeTab(panel.getEl().id);
36715 }else if (!preservePanel){
36716 this.bodyEl.dom.removeChild(panel.getEl().dom);
36718 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36719 var p = this.panels.first();
36720 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36721 tempEl.appendChild(p.getEl().dom);
36722 this.bodyEl.update("");
36723 this.bodyEl.dom.appendChild(p.getEl().dom);
36725 this.updateTitle(p.getTitle());
36727 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36728 this.setActivePanel(p);
36730 panel.setRegion(null);
36731 if(this.activePanel == panel){
36732 this.activePanel = null;
36734 if(this.config.autoDestroy !== false && preservePanel !== true){
36735 try{panel.destroy();}catch(e){}
36737 this.fireEvent("panelremoved", this, panel);
36742 * Returns the TabPanel component used by this region
36743 * @return {Roo.TabPanel}
36745 getTabs : function(){
36749 createTool : function(parentEl, className){
36750 var btn = Roo.DomHelper.append(parentEl, {
36752 cls: "x-layout-tools-button",
36755 cls: "roo-layout-tools-button-inner " + className,
36759 btn.addClassOnOver("roo-layout-tools-button-over");
36764 * Ext JS Library 1.1.1
36765 * Copyright(c) 2006-2007, Ext JS, LLC.
36767 * Originally Released Under LGPL - original licence link has changed is not relivant.
36770 * <script type="text/javascript">
36776 * @class Roo.SplitLayoutRegion
36777 * @extends Roo.LayoutRegion
36778 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36780 Roo.bootstrap.layout.Split = function(config){
36781 this.cursor = config.cursor;
36782 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36785 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36787 splitTip : "Drag to resize.",
36788 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36789 useSplitTips : false,
36791 applyConfig : function(config){
36792 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36795 onRender : function(ctr,pos) {
36797 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36798 if(!this.config.split){
36803 var splitEl = Roo.DomHelper.append(ctr.dom, {
36805 id: this.el.id + "-split",
36806 cls: "roo-layout-split roo-layout-split-"+this.position,
36809 /** The SplitBar for this region
36810 * @type Roo.SplitBar */
36811 // does not exist yet...
36812 Roo.log([this.position, this.orientation]);
36814 this.split = new Roo.bootstrap.SplitBar({
36815 dragElement : splitEl,
36816 resizingElement: this.el,
36817 orientation : this.orientation
36820 this.split.on("moved", this.onSplitMove, this);
36821 this.split.useShim = this.config.useShim === true;
36822 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36823 if(this.useSplitTips){
36824 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36826 //if(config.collapsible){
36827 // this.split.el.on("dblclick", this.collapse, this);
36830 if(typeof this.config.minSize != "undefined"){
36831 this.split.minSize = this.config.minSize;
36833 if(typeof this.config.maxSize != "undefined"){
36834 this.split.maxSize = this.config.maxSize;
36836 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36837 this.hideSplitter();
36842 getHMaxSize : function(){
36843 var cmax = this.config.maxSize || 10000;
36844 var center = this.mgr.getRegion("center");
36845 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36848 getVMaxSize : function(){
36849 var cmax = this.config.maxSize || 10000;
36850 var center = this.mgr.getRegion("center");
36851 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36854 onSplitMove : function(split, newSize){
36855 this.fireEvent("resized", this, newSize);
36859 * Returns the {@link Roo.SplitBar} for this region.
36860 * @return {Roo.SplitBar}
36862 getSplitBar : function(){
36867 this.hideSplitter();
36868 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36871 hideSplitter : function(){
36873 this.split.el.setLocation(-2000,-2000);
36874 this.split.el.hide();
36880 this.split.el.show();
36882 Roo.bootstrap.layout.Split.superclass.show.call(this);
36885 beforeSlide: function(){
36886 if(Roo.isGecko){// firefox overflow auto bug workaround
36887 this.bodyEl.clip();
36889 this.tabs.bodyEl.clip();
36891 if(this.activePanel){
36892 this.activePanel.getEl().clip();
36894 if(this.activePanel.beforeSlide){
36895 this.activePanel.beforeSlide();
36901 afterSlide : function(){
36902 if(Roo.isGecko){// firefox overflow auto bug workaround
36903 this.bodyEl.unclip();
36905 this.tabs.bodyEl.unclip();
36907 if(this.activePanel){
36908 this.activePanel.getEl().unclip();
36909 if(this.activePanel.afterSlide){
36910 this.activePanel.afterSlide();
36916 initAutoHide : function(){
36917 if(this.autoHide !== false){
36918 if(!this.autoHideHd){
36919 var st = new Roo.util.DelayedTask(this.slideIn, this);
36920 this.autoHideHd = {
36921 "mouseout": function(e){
36922 if(!e.within(this.el, true)){
36926 "mouseover" : function(e){
36932 this.el.on(this.autoHideHd);
36936 clearAutoHide : function(){
36937 if(this.autoHide !== false){
36938 this.el.un("mouseout", this.autoHideHd.mouseout);
36939 this.el.un("mouseover", this.autoHideHd.mouseover);
36943 clearMonitor : function(){
36944 Roo.get(document).un("click", this.slideInIf, this);
36947 // these names are backwards but not changed for compat
36948 slideOut : function(){
36949 if(this.isSlid || this.el.hasActiveFx()){
36952 this.isSlid = true;
36953 if(this.collapseBtn){
36954 this.collapseBtn.hide();
36956 this.closeBtnState = this.closeBtn.getStyle('display');
36957 this.closeBtn.hide();
36959 this.stickBtn.show();
36962 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36963 this.beforeSlide();
36964 this.el.setStyle("z-index", 10001);
36965 this.el.slideIn(this.getSlideAnchor(), {
36966 callback: function(){
36968 this.initAutoHide();
36969 Roo.get(document).on("click", this.slideInIf, this);
36970 this.fireEvent("slideshow", this);
36977 afterSlideIn : function(){
36978 this.clearAutoHide();
36979 this.isSlid = false;
36980 this.clearMonitor();
36981 this.el.setStyle("z-index", "");
36982 if(this.collapseBtn){
36983 this.collapseBtn.show();
36985 this.closeBtn.setStyle('display', this.closeBtnState);
36987 this.stickBtn.hide();
36989 this.fireEvent("slidehide", this);
36992 slideIn : function(cb){
36993 if(!this.isSlid || this.el.hasActiveFx()){
36997 this.isSlid = false;
36998 this.beforeSlide();
36999 this.el.slideOut(this.getSlideAnchor(), {
37000 callback: function(){
37001 this.el.setLeftTop(-10000, -10000);
37003 this.afterSlideIn();
37011 slideInIf : function(e){
37012 if(!e.within(this.el)){
37017 animateCollapse : function(){
37018 this.beforeSlide();
37019 this.el.setStyle("z-index", 20000);
37020 var anchor = this.getSlideAnchor();
37021 this.el.slideOut(anchor, {
37022 callback : function(){
37023 this.el.setStyle("z-index", "");
37024 this.collapsedEl.slideIn(anchor, {duration:.3});
37026 this.el.setLocation(-10000,-10000);
37028 this.fireEvent("collapsed", this);
37035 animateExpand : function(){
37036 this.beforeSlide();
37037 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
37038 this.el.setStyle("z-index", 20000);
37039 this.collapsedEl.hide({
37042 this.el.slideIn(this.getSlideAnchor(), {
37043 callback : function(){
37044 this.el.setStyle("z-index", "");
37047 this.split.el.show();
37049 this.fireEvent("invalidated", this);
37050 this.fireEvent("expanded", this);
37078 getAnchor : function(){
37079 return this.anchors[this.position];
37082 getCollapseAnchor : function(){
37083 return this.canchors[this.position];
37086 getSlideAnchor : function(){
37087 return this.sanchors[this.position];
37090 getAlignAdj : function(){
37091 var cm = this.cmargins;
37092 switch(this.position){
37108 getExpandAdj : function(){
37109 var c = this.collapsedEl, cm = this.cmargins;
37110 switch(this.position){
37112 return [-(cm.right+c.getWidth()+cm.left), 0];
37115 return [cm.right+c.getWidth()+cm.left, 0];
37118 return [0, -(cm.top+cm.bottom+c.getHeight())];
37121 return [0, cm.top+cm.bottom+c.getHeight()];
37127 * Ext JS Library 1.1.1
37128 * Copyright(c) 2006-2007, Ext JS, LLC.
37130 * Originally Released Under LGPL - original licence link has changed is not relivant.
37133 * <script type="text/javascript">
37136 * These classes are private internal classes
37138 Roo.bootstrap.layout.Center = function(config){
37139 config.region = "center";
37140 Roo.bootstrap.layout.Region.call(this, config);
37141 this.visible = true;
37142 this.minWidth = config.minWidth || 20;
37143 this.minHeight = config.minHeight || 20;
37146 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37148 // center panel can't be hidden
37152 // center panel can't be hidden
37155 getMinWidth: function(){
37156 return this.minWidth;
37159 getMinHeight: function(){
37160 return this.minHeight;
37174 Roo.bootstrap.layout.North = function(config)
37176 config.region = 'north';
37177 config.cursor = 'n-resize';
37179 Roo.bootstrap.layout.Split.call(this, config);
37183 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37184 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37185 this.split.el.addClass("roo-layout-split-v");
37187 var size = config.initialSize || config.height;
37188 if(typeof size != "undefined"){
37189 this.el.setHeight(size);
37192 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37194 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37198 getBox : function(){
37199 if(this.collapsed){
37200 return this.collapsedEl.getBox();
37202 var box = this.el.getBox();
37204 box.height += this.split.el.getHeight();
37209 updateBox : function(box){
37210 if(this.split && !this.collapsed){
37211 box.height -= this.split.el.getHeight();
37212 this.split.el.setLeft(box.x);
37213 this.split.el.setTop(box.y+box.height);
37214 this.split.el.setWidth(box.width);
37216 if(this.collapsed){
37217 this.updateBody(box.width, null);
37219 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37227 Roo.bootstrap.layout.South = function(config){
37228 config.region = 'south';
37229 config.cursor = 's-resize';
37230 Roo.bootstrap.layout.Split.call(this, config);
37232 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37233 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37234 this.split.el.addClass("roo-layout-split-v");
37236 var size = config.initialSize || config.height;
37237 if(typeof size != "undefined"){
37238 this.el.setHeight(size);
37242 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37243 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37244 getBox : function(){
37245 if(this.collapsed){
37246 return this.collapsedEl.getBox();
37248 var box = this.el.getBox();
37250 var sh = this.split.el.getHeight();
37257 updateBox : function(box){
37258 if(this.split && !this.collapsed){
37259 var sh = this.split.el.getHeight();
37262 this.split.el.setLeft(box.x);
37263 this.split.el.setTop(box.y-sh);
37264 this.split.el.setWidth(box.width);
37266 if(this.collapsed){
37267 this.updateBody(box.width, null);
37269 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37273 Roo.bootstrap.layout.East = function(config){
37274 config.region = "east";
37275 config.cursor = "e-resize";
37276 Roo.bootstrap.layout.Split.call(this, config);
37278 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37279 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37280 this.split.el.addClass("roo-layout-split-h");
37282 var size = config.initialSize || config.width;
37283 if(typeof size != "undefined"){
37284 this.el.setWidth(size);
37287 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37288 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37289 getBox : function(){
37290 if(this.collapsed){
37291 return this.collapsedEl.getBox();
37293 var box = this.el.getBox();
37295 var sw = this.split.el.getWidth();
37302 updateBox : function(box){
37303 if(this.split && !this.collapsed){
37304 var sw = this.split.el.getWidth();
37306 this.split.el.setLeft(box.x);
37307 this.split.el.setTop(box.y);
37308 this.split.el.setHeight(box.height);
37311 if(this.collapsed){
37312 this.updateBody(null, box.height);
37314 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37318 Roo.bootstrap.layout.West = function(config){
37319 config.region = "west";
37320 config.cursor = "w-resize";
37322 Roo.bootstrap.layout.Split.call(this, config);
37324 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37325 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37326 this.split.el.addClass("roo-layout-split-h");
37330 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37331 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37333 onRender: function(ctr, pos)
37335 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37336 var size = this.config.initialSize || this.config.width;
37337 if(typeof size != "undefined"){
37338 this.el.setWidth(size);
37342 getBox : function(){
37343 if(this.collapsed){
37344 return this.collapsedEl.getBox();
37346 var box = this.el.getBox();
37348 box.width += this.split.el.getWidth();
37353 updateBox : function(box){
37354 if(this.split && !this.collapsed){
37355 var sw = this.split.el.getWidth();
37357 this.split.el.setLeft(box.x+box.width);
37358 this.split.el.setTop(box.y);
37359 this.split.el.setHeight(box.height);
37361 if(this.collapsed){
37362 this.updateBody(null, box.height);
37364 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37366 });Roo.namespace("Roo.bootstrap.panel");/*
37368 * Ext JS Library 1.1.1
37369 * Copyright(c) 2006-2007, Ext JS, LLC.
37371 * Originally Released Under LGPL - original licence link has changed is not relivant.
37374 * <script type="text/javascript">
37377 * @class Roo.ContentPanel
37378 * @extends Roo.util.Observable
37379 * A basic ContentPanel element.
37380 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37381 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37382 * @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
37383 * @cfg {Boolean} closable True if the panel can be closed/removed
37384 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37385 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37386 * @cfg {Toolbar} toolbar A toolbar for this panel
37387 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37388 * @cfg {String} title The title for this panel
37389 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37390 * @cfg {String} url Calls {@link #setUrl} with this value
37391 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37392 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37393 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37394 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37395 * @cfg {Boolean} badges render the badges
37398 * Create a new ContentPanel.
37399 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37400 * @param {String/Object} config A string to set only the title or a config object
37401 * @param {String} content (optional) Set the HTML content for this panel
37402 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37404 Roo.bootstrap.panel.Content = function( config){
37406 this.tpl = config.tpl || false;
37408 var el = config.el;
37409 var content = config.content;
37411 if(config.autoCreate){ // xtype is available if this is called from factory
37414 this.el = Roo.get(el);
37415 if(!this.el && config && config.autoCreate){
37416 if(typeof config.autoCreate == "object"){
37417 if(!config.autoCreate.id){
37418 config.autoCreate.id = config.id||el;
37420 this.el = Roo.DomHelper.append(document.body,
37421 config.autoCreate, true);
37423 var elcfg = { tag: "div",
37424 cls: "roo-layout-inactive-content",
37428 elcfg.html = config.html;
37432 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37435 this.closable = false;
37436 this.loaded = false;
37437 this.active = false;
37440 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37442 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37444 this.wrapEl = this.el; //this.el.wrap();
37446 if (config.toolbar.items) {
37447 ti = config.toolbar.items ;
37448 delete config.toolbar.items ;
37452 this.toolbar.render(this.wrapEl, 'before');
37453 for(var i =0;i < ti.length;i++) {
37454 // Roo.log(['add child', items[i]]);
37455 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37457 this.toolbar.items = nitems;
37458 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37459 delete config.toolbar;
37463 // xtype created footer. - not sure if will work as we normally have to render first..
37464 if (this.footer && !this.footer.el && this.footer.xtype) {
37465 if (!this.wrapEl) {
37466 this.wrapEl = this.el.wrap();
37469 this.footer.container = this.wrapEl.createChild();
37471 this.footer = Roo.factory(this.footer, Roo);
37476 if(typeof config == "string"){
37477 this.title = config;
37479 Roo.apply(this, config);
37483 this.resizeEl = Roo.get(this.resizeEl, true);
37485 this.resizeEl = this.el;
37487 // handle view.xtype
37495 * Fires when this panel is activated.
37496 * @param {Roo.ContentPanel} this
37500 * @event deactivate
37501 * Fires when this panel is activated.
37502 * @param {Roo.ContentPanel} this
37504 "deactivate" : true,
37508 * Fires when this panel is resized if fitToFrame is true.
37509 * @param {Roo.ContentPanel} this
37510 * @param {Number} width The width after any component adjustments
37511 * @param {Number} height The height after any component adjustments
37517 * Fires when this tab is created
37518 * @param {Roo.ContentPanel} this
37529 if(this.autoScroll){
37530 this.resizeEl.setStyle("overflow", "auto");
37532 // fix randome scrolling
37533 //this.el.on('scroll', function() {
37534 // Roo.log('fix random scolling');
37535 // this.scrollTo('top',0);
37538 content = content || this.content;
37540 this.setContent(content);
37542 if(config && config.url){
37543 this.setUrl(this.url, this.params, this.loadOnce);
37548 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37550 if (this.view && typeof(this.view.xtype) != 'undefined') {
37551 this.view.el = this.el.appendChild(document.createElement("div"));
37552 this.view = Roo.factory(this.view);
37553 this.view.render && this.view.render(false, '');
37557 this.fireEvent('render', this);
37560 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37564 setRegion : function(region){
37565 this.region = region;
37566 this.setActiveClass(region && !this.background);
37570 setActiveClass: function(state)
37573 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37574 this.el.setStyle('position','relative');
37576 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37577 this.el.setStyle('position', 'absolute');
37582 * Returns the toolbar for this Panel if one was configured.
37583 * @return {Roo.Toolbar}
37585 getToolbar : function(){
37586 return this.toolbar;
37589 setActiveState : function(active)
37591 this.active = active;
37592 this.setActiveClass(active);
37594 if(this.fireEvent("deactivate", this) === false){
37599 this.fireEvent("activate", this);
37603 * Updates this panel's element
37604 * @param {String} content The new content
37605 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37607 setContent : function(content, loadScripts){
37608 this.el.update(content, loadScripts);
37611 ignoreResize : function(w, h){
37612 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37615 this.lastSize = {width: w, height: h};
37620 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37621 * @return {Roo.UpdateManager} The UpdateManager
37623 getUpdateManager : function(){
37624 return this.el.getUpdateManager();
37627 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37628 * @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:
37631 url: "your-url.php",
37632 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37633 callback: yourFunction,
37634 scope: yourObject, //(optional scope)
37637 text: "Loading...",
37642 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37643 * 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.
37644 * @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}
37645 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37646 * @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.
37647 * @return {Roo.ContentPanel} this
37650 var um = this.el.getUpdateManager();
37651 um.update.apply(um, arguments);
37657 * 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.
37658 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37659 * @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)
37660 * @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)
37661 * @return {Roo.UpdateManager} The UpdateManager
37663 setUrl : function(url, params, loadOnce){
37664 if(this.refreshDelegate){
37665 this.removeListener("activate", this.refreshDelegate);
37667 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37668 this.on("activate", this.refreshDelegate);
37669 return this.el.getUpdateManager();
37672 _handleRefresh : function(url, params, loadOnce){
37673 if(!loadOnce || !this.loaded){
37674 var updater = this.el.getUpdateManager();
37675 updater.update(url, params, this._setLoaded.createDelegate(this));
37679 _setLoaded : function(){
37680 this.loaded = true;
37684 * Returns this panel's id
37687 getId : function(){
37692 * Returns this panel's element - used by regiosn to add.
37693 * @return {Roo.Element}
37695 getEl : function(){
37696 return this.wrapEl || this.el;
37701 adjustForComponents : function(width, height)
37703 //Roo.log('adjustForComponents ');
37704 if(this.resizeEl != this.el){
37705 width -= this.el.getFrameWidth('lr');
37706 height -= this.el.getFrameWidth('tb');
37709 var te = this.toolbar.getEl();
37710 te.setWidth(width);
37711 height -= te.getHeight();
37714 var te = this.footer.getEl();
37715 te.setWidth(width);
37716 height -= te.getHeight();
37720 if(this.adjustments){
37721 width += this.adjustments[0];
37722 height += this.adjustments[1];
37724 return {"width": width, "height": height};
37727 setSize : function(width, height){
37728 if(this.fitToFrame && !this.ignoreResize(width, height)){
37729 if(this.fitContainer && this.resizeEl != this.el){
37730 this.el.setSize(width, height);
37732 var size = this.adjustForComponents(width, height);
37733 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37734 this.fireEvent('resize', this, size.width, size.height);
37739 * Returns this panel's title
37742 getTitle : function(){
37744 if (typeof(this.title) != 'object') {
37749 for (var k in this.title) {
37750 if (!this.title.hasOwnProperty(k)) {
37754 if (k.indexOf('-') >= 0) {
37755 var s = k.split('-');
37756 for (var i = 0; i<s.length; i++) {
37757 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37760 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37767 * Set this panel's title
37768 * @param {String} title
37770 setTitle : function(title){
37771 this.title = title;
37773 this.region.updatePanelTitle(this, title);
37778 * Returns true is this panel was configured to be closable
37779 * @return {Boolean}
37781 isClosable : function(){
37782 return this.closable;
37785 beforeSlide : function(){
37787 this.resizeEl.clip();
37790 afterSlide : function(){
37792 this.resizeEl.unclip();
37796 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37797 * Will fail silently if the {@link #setUrl} method has not been called.
37798 * This does not activate the panel, just updates its content.
37800 refresh : function(){
37801 if(this.refreshDelegate){
37802 this.loaded = false;
37803 this.refreshDelegate();
37808 * Destroys this panel
37810 destroy : function(){
37811 this.el.removeAllListeners();
37812 var tempEl = document.createElement("span");
37813 tempEl.appendChild(this.el.dom);
37814 tempEl.innerHTML = "";
37820 * form - if the content panel contains a form - this is a reference to it.
37821 * @type {Roo.form.Form}
37825 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37826 * This contains a reference to it.
37832 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37842 * @param {Object} cfg Xtype definition of item to add.
37846 getChildContainer: function () {
37847 return this.getEl();
37852 var ret = new Roo.factory(cfg);
37857 if (cfg.xtype.match(/^Form$/)) {
37860 //if (this.footer) {
37861 // el = this.footer.container.insertSibling(false, 'before');
37863 el = this.el.createChild();
37866 this.form = new Roo.form.Form(cfg);
37869 if ( this.form.allItems.length) {
37870 this.form.render(el.dom);
37874 // should only have one of theses..
37875 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37876 // views.. should not be just added - used named prop 'view''
37878 cfg.el = this.el.appendChild(document.createElement("div"));
37881 var ret = new Roo.factory(cfg);
37883 ret.render && ret.render(false, ''); // render blank..
37893 * @class Roo.bootstrap.panel.Grid
37894 * @extends Roo.bootstrap.panel.Content
37896 * Create a new GridPanel.
37897 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37898 * @param {Object} config A the config object
37904 Roo.bootstrap.panel.Grid = function(config)
37908 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37909 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37911 config.el = this.wrapper;
37912 //this.el = this.wrapper;
37914 if (config.container) {
37915 // ctor'ed from a Border/panel.grid
37918 this.wrapper.setStyle("overflow", "hidden");
37919 this.wrapper.addClass('roo-grid-container');
37924 if(config.toolbar){
37925 var tool_el = this.wrapper.createChild();
37926 this.toolbar = Roo.factory(config.toolbar);
37928 if (config.toolbar.items) {
37929 ti = config.toolbar.items ;
37930 delete config.toolbar.items ;
37934 this.toolbar.render(tool_el);
37935 for(var i =0;i < ti.length;i++) {
37936 // Roo.log(['add child', items[i]]);
37937 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37939 this.toolbar.items = nitems;
37941 delete config.toolbar;
37944 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37945 config.grid.scrollBody = true;;
37946 config.grid.monitorWindowResize = false; // turn off autosizing
37947 config.grid.autoHeight = false;
37948 config.grid.autoWidth = false;
37950 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37952 if (config.background) {
37953 // render grid on panel activation (if panel background)
37954 this.on('activate', function(gp) {
37955 if (!gp.grid.rendered) {
37956 gp.grid.render(this.wrapper);
37957 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37962 this.grid.render(this.wrapper);
37963 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37966 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37967 // ??? needed ??? config.el = this.wrapper;
37972 // xtype created footer. - not sure if will work as we normally have to render first..
37973 if (this.footer && !this.footer.el && this.footer.xtype) {
37975 var ctr = this.grid.getView().getFooterPanel(true);
37976 this.footer.dataSource = this.grid.dataSource;
37977 this.footer = Roo.factory(this.footer, Roo);
37978 this.footer.render(ctr);
37988 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37989 getId : function(){
37990 return this.grid.id;
37994 * Returns the grid for this panel
37995 * @return {Roo.bootstrap.Table}
37997 getGrid : function(){
38001 setSize : function(width, height){
38002 if(!this.ignoreResize(width, height)){
38003 var grid = this.grid;
38004 var size = this.adjustForComponents(width, height);
38005 var gridel = grid.getGridEl();
38006 gridel.setSize(size.width, size.height);
38008 var thd = grid.getGridEl().select('thead',true).first();
38009 var tbd = grid.getGridEl().select('tbody', true).first();
38011 tbd.setSize(width, height - thd.getHeight());
38020 beforeSlide : function(){
38021 this.grid.getView().scroller.clip();
38024 afterSlide : function(){
38025 this.grid.getView().scroller.unclip();
38028 destroy : function(){
38029 this.grid.destroy();
38031 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
38036 * @class Roo.bootstrap.panel.Nest
38037 * @extends Roo.bootstrap.panel.Content
38039 * Create a new Panel, that can contain a layout.Border.
38042 * @param {Roo.BorderLayout} layout The layout for this panel
38043 * @param {String/Object} config A string to set only the title or a config object
38045 Roo.bootstrap.panel.Nest = function(config)
38047 // construct with only one argument..
38048 /* FIXME - implement nicer consturctors
38049 if (layout.layout) {
38051 layout = config.layout;
38052 delete config.layout;
38054 if (layout.xtype && !layout.getEl) {
38055 // then layout needs constructing..
38056 layout = Roo.factory(layout, Roo);
38060 config.el = config.layout.getEl();
38062 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38064 config.layout.monitorWindowResize = false; // turn off autosizing
38065 this.layout = config.layout;
38066 this.layout.getEl().addClass("roo-layout-nested-layout");
38067 this.layout.parent = this;
38074 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38076 setSize : function(width, height){
38077 if(!this.ignoreResize(width, height)){
38078 var size = this.adjustForComponents(width, height);
38079 var el = this.layout.getEl();
38080 if (size.height < 1) {
38081 el.setWidth(size.width);
38083 el.setSize(size.width, size.height);
38085 var touch = el.dom.offsetWidth;
38086 this.layout.layout();
38087 // ie requires a double layout on the first pass
38088 if(Roo.isIE && !this.initialized){
38089 this.initialized = true;
38090 this.layout.layout();
38095 // activate all subpanels if not currently active..
38097 setActiveState : function(active){
38098 this.active = active;
38099 this.setActiveClass(active);
38102 this.fireEvent("deactivate", this);
38106 this.fireEvent("activate", this);
38107 // not sure if this should happen before or after..
38108 if (!this.layout) {
38109 return; // should not happen..
38112 for (var r in this.layout.regions) {
38113 reg = this.layout.getRegion(r);
38114 if (reg.getActivePanel()) {
38115 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38116 reg.setActivePanel(reg.getActivePanel());
38119 if (!reg.panels.length) {
38122 reg.showPanel(reg.getPanel(0));
38131 * Returns the nested BorderLayout for this panel
38132 * @return {Roo.BorderLayout}
38134 getLayout : function(){
38135 return this.layout;
38139 * Adds a xtype elements to the layout of the nested panel
38143 xtype : 'ContentPanel',
38150 xtype : 'NestedLayoutPanel',
38156 items : [ ... list of content panels or nested layout panels.. ]
38160 * @param {Object} cfg Xtype definition of item to add.
38162 addxtype : function(cfg) {
38163 return this.layout.addxtype(cfg);
38168 * Ext JS Library 1.1.1
38169 * Copyright(c) 2006-2007, Ext JS, LLC.
38171 * Originally Released Under LGPL - original licence link has changed is not relivant.
38174 * <script type="text/javascript">
38177 * @class Roo.TabPanel
38178 * @extends Roo.util.Observable
38179 * A lightweight tab container.
38183 // basic tabs 1, built from existing content
38184 var tabs = new Roo.TabPanel("tabs1");
38185 tabs.addTab("script", "View Script");
38186 tabs.addTab("markup", "View Markup");
38187 tabs.activate("script");
38189 // more advanced tabs, built from javascript
38190 var jtabs = new Roo.TabPanel("jtabs");
38191 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38193 // set up the UpdateManager
38194 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38195 var updater = tab2.getUpdateManager();
38196 updater.setDefaultUrl("ajax1.htm");
38197 tab2.on('activate', updater.refresh, updater, true);
38199 // Use setUrl for Ajax loading
38200 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38201 tab3.setUrl("ajax2.htm", null, true);
38204 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38207 jtabs.activate("jtabs-1");
38210 * Create a new TabPanel.
38211 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38212 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38214 Roo.bootstrap.panel.Tabs = function(config){
38216 * The container element for this TabPanel.
38217 * @type Roo.Element
38219 this.el = Roo.get(config.el);
38222 if(typeof config == "boolean"){
38223 this.tabPosition = config ? "bottom" : "top";
38225 Roo.apply(this, config);
38229 if(this.tabPosition == "bottom"){
38230 // if tabs are at the bottom = create the body first.
38231 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38232 this.el.addClass("roo-tabs-bottom");
38234 // next create the tabs holders
38236 if (this.tabPosition == "west"){
38238 var reg = this.region; // fake it..
38240 if (!reg.mgr.parent) {
38243 reg = reg.mgr.parent.region;
38245 Roo.log("got nest?");
38247 if (reg.mgr.getRegion('west')) {
38248 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38249 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38250 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38251 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38252 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38260 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38261 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38262 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38263 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38268 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38271 // finally - if tabs are at the top, then create the body last..
38272 if(this.tabPosition != "bottom"){
38273 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38274 * @type Roo.Element
38276 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38277 this.el.addClass("roo-tabs-top");
38281 this.bodyEl.setStyle("position", "relative");
38283 this.active = null;
38284 this.activateDelegate = this.activate.createDelegate(this);
38289 * Fires when the active tab changes
38290 * @param {Roo.TabPanel} this
38291 * @param {Roo.TabPanelItem} activePanel The new active tab
38295 * @event beforetabchange
38296 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38297 * @param {Roo.TabPanel} this
38298 * @param {Object} e Set cancel to true on this object to cancel the tab change
38299 * @param {Roo.TabPanelItem} tab The tab being changed to
38301 "beforetabchange" : true
38304 Roo.EventManager.onWindowResize(this.onResize, this);
38305 this.cpad = this.el.getPadding("lr");
38306 this.hiddenCount = 0;
38309 // toolbar on the tabbar support...
38310 if (this.toolbar) {
38311 alert("no toolbar support yet");
38312 this.toolbar = false;
38314 var tcfg = this.toolbar;
38315 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38316 this.toolbar = new Roo.Toolbar(tcfg);
38317 if (Roo.isSafari) {
38318 var tbl = tcfg.container.child('table', true);
38319 tbl.setAttribute('width', '100%');
38327 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38330 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38332 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38334 tabPosition : "top",
38336 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38338 currentTabWidth : 0,
38340 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38344 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38348 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38350 preferredTabWidth : 175,
38352 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38354 resizeTabs : false,
38356 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38358 monitorResize : true,
38360 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38362 toolbar : false, // set by caller..
38364 region : false, /// set by caller
38366 disableTooltips : true, // not used yet...
38369 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38370 * @param {String} id The id of the div to use <b>or create</b>
38371 * @param {String} text The text for the tab
38372 * @param {String} content (optional) Content to put in the TabPanelItem body
38373 * @param {Boolean} closable (optional) True to create a close icon on the tab
38374 * @return {Roo.TabPanelItem} The created TabPanelItem
38376 addTab : function(id, text, content, closable, tpl)
38378 var item = new Roo.bootstrap.panel.TabItem({
38382 closable : closable,
38385 this.addTabItem(item);
38387 item.setContent(content);
38393 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38394 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38395 * @return {Roo.TabPanelItem}
38397 getTab : function(id){
38398 return this.items[id];
38402 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38403 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38405 hideTab : function(id){
38406 var t = this.items[id];
38409 this.hiddenCount++;
38410 this.autoSizeTabs();
38415 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38416 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38418 unhideTab : function(id){
38419 var t = this.items[id];
38421 t.setHidden(false);
38422 this.hiddenCount--;
38423 this.autoSizeTabs();
38428 * Adds an existing {@link Roo.TabPanelItem}.
38429 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38431 addTabItem : function(item)
38433 this.items[item.id] = item;
38434 this.items.push(item);
38435 this.autoSizeTabs();
38436 // if(this.resizeTabs){
38437 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38438 // this.autoSizeTabs();
38440 // item.autoSize();
38445 * Removes a {@link Roo.TabPanelItem}.
38446 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38448 removeTab : function(id){
38449 var items = this.items;
38450 var tab = items[id];
38451 if(!tab) { return; }
38452 var index = items.indexOf(tab);
38453 if(this.active == tab && items.length > 1){
38454 var newTab = this.getNextAvailable(index);
38459 this.stripEl.dom.removeChild(tab.pnode.dom);
38460 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38461 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38463 items.splice(index, 1);
38464 delete this.items[tab.id];
38465 tab.fireEvent("close", tab);
38466 tab.purgeListeners();
38467 this.autoSizeTabs();
38470 getNextAvailable : function(start){
38471 var items = this.items;
38473 // look for a next tab that will slide over to
38474 // replace the one being removed
38475 while(index < items.length){
38476 var item = items[++index];
38477 if(item && !item.isHidden()){
38481 // if one isn't found select the previous tab (on the left)
38484 var item = items[--index];
38485 if(item && !item.isHidden()){
38493 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38494 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38496 disableTab : function(id){
38497 var tab = this.items[id];
38498 if(tab && this.active != tab){
38504 * Enables a {@link Roo.TabPanelItem} that is disabled.
38505 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38507 enableTab : function(id){
38508 var tab = this.items[id];
38513 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38514 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38515 * @return {Roo.TabPanelItem} The TabPanelItem.
38517 activate : function(id)
38519 //Roo.log('activite:' + id);
38521 var tab = this.items[id];
38525 if(tab == this.active || tab.disabled){
38529 this.fireEvent("beforetabchange", this, e, tab);
38530 if(e.cancel !== true && !tab.disabled){
38532 this.active.hide();
38534 this.active = this.items[id];
38535 this.active.show();
38536 this.fireEvent("tabchange", this, this.active);
38542 * Gets the active {@link Roo.TabPanelItem}.
38543 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38545 getActiveTab : function(){
38546 return this.active;
38550 * Updates the tab body element to fit the height of the container element
38551 * for overflow scrolling
38552 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38554 syncHeight : function(targetHeight){
38555 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38556 var bm = this.bodyEl.getMargins();
38557 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38558 this.bodyEl.setHeight(newHeight);
38562 onResize : function(){
38563 if(this.monitorResize){
38564 this.autoSizeTabs();
38569 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38571 beginUpdate : function(){
38572 this.updating = true;
38576 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38578 endUpdate : function(){
38579 this.updating = false;
38580 this.autoSizeTabs();
38584 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38586 autoSizeTabs : function()
38588 var count = this.items.length;
38589 var vcount = count - this.hiddenCount;
38592 this.stripEl.hide();
38594 this.stripEl.show();
38597 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38602 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38603 var availWidth = Math.floor(w / vcount);
38604 var b = this.stripBody;
38605 if(b.getWidth() > w){
38606 var tabs = this.items;
38607 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38608 if(availWidth < this.minTabWidth){
38609 /*if(!this.sleft){ // incomplete scrolling code
38610 this.createScrollButtons();
38613 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38616 if(this.currentTabWidth < this.preferredTabWidth){
38617 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38623 * Returns the number of tabs in this TabPanel.
38626 getCount : function(){
38627 return this.items.length;
38631 * Resizes all the tabs to the passed width
38632 * @param {Number} The new width
38634 setTabWidth : function(width){
38635 this.currentTabWidth = width;
38636 for(var i = 0, len = this.items.length; i < len; i++) {
38637 if(!this.items[i].isHidden()) {
38638 this.items[i].setWidth(width);
38644 * Destroys this TabPanel
38645 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38647 destroy : function(removeEl){
38648 Roo.EventManager.removeResizeListener(this.onResize, this);
38649 for(var i = 0, len = this.items.length; i < len; i++){
38650 this.items[i].purgeListeners();
38652 if(removeEl === true){
38653 this.el.update("");
38658 createStrip : function(container)
38660 var strip = document.createElement("nav");
38661 strip.className = Roo.bootstrap.version == 4 ?
38662 "navbar-light bg-light" :
38663 "navbar navbar-default"; //"x-tabs-wrap";
38664 container.appendChild(strip);
38668 createStripList : function(strip)
38670 // div wrapper for retard IE
38671 // returns the "tr" element.
38672 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38673 //'<div class="x-tabs-strip-wrap">'+
38674 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38675 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38676 return strip.firstChild; //.firstChild.firstChild.firstChild;
38678 createBody : function(container)
38680 var body = document.createElement("div");
38681 Roo.id(body, "tab-body");
38682 //Roo.fly(body).addClass("x-tabs-body");
38683 Roo.fly(body).addClass("tab-content");
38684 container.appendChild(body);
38687 createItemBody :function(bodyEl, id){
38688 var body = Roo.getDom(id);
38690 body = document.createElement("div");
38693 //Roo.fly(body).addClass("x-tabs-item-body");
38694 Roo.fly(body).addClass("tab-pane");
38695 bodyEl.insertBefore(body, bodyEl.firstChild);
38699 createStripElements : function(stripEl, text, closable, tpl)
38701 var td = document.createElement("li"); // was td..
38702 td.className = 'nav-item';
38704 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38707 stripEl.appendChild(td);
38709 td.className = "x-tabs-closable";
38710 if(!this.closeTpl){
38711 this.closeTpl = new Roo.Template(
38712 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38713 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38714 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38717 var el = this.closeTpl.overwrite(td, {"text": text});
38718 var close = el.getElementsByTagName("div")[0];
38719 var inner = el.getElementsByTagName("em")[0];
38720 return {"el": el, "close": close, "inner": inner};
38723 // not sure what this is..
38724 // if(!this.tabTpl){
38725 //this.tabTpl = new Roo.Template(
38726 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38727 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38729 // this.tabTpl = new Roo.Template(
38730 // '<a href="#">' +
38731 // '<span unselectable="on"' +
38732 // (this.disableTooltips ? '' : ' title="{text}"') +
38733 // ' >{text}</span></a>'
38739 var template = tpl || this.tabTpl || false;
38742 template = new Roo.Template(
38743 Roo.bootstrap.version == 4 ?
38745 '<a class="nav-link" href="#" unselectable="on"' +
38746 (this.disableTooltips ? '' : ' title="{text}"') +
38749 '<a class="nav-link" href="#">' +
38750 '<span unselectable="on"' +
38751 (this.disableTooltips ? '' : ' title="{text}"') +
38752 ' >{text}</span></a>'
38757 switch (typeof(template)) {
38761 template = new Roo.Template(template);
38767 var el = template.overwrite(td, {"text": text});
38769 var inner = el.getElementsByTagName("span")[0];
38771 return {"el": el, "inner": inner};
38779 * @class Roo.TabPanelItem
38780 * @extends Roo.util.Observable
38781 * Represents an individual item (tab plus body) in a TabPanel.
38782 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38783 * @param {String} id The id of this TabPanelItem
38784 * @param {String} text The text for the tab of this TabPanelItem
38785 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38787 Roo.bootstrap.panel.TabItem = function(config){
38789 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38790 * @type Roo.TabPanel
38792 this.tabPanel = config.panel;
38794 * The id for this TabPanelItem
38797 this.id = config.id;
38799 this.disabled = false;
38801 this.text = config.text;
38803 this.loaded = false;
38804 this.closable = config.closable;
38807 * The body element for this TabPanelItem.
38808 * @type Roo.Element
38810 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38811 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38812 this.bodyEl.setStyle("display", "block");
38813 this.bodyEl.setStyle("zoom", "1");
38814 //this.hideAction();
38816 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38818 this.el = Roo.get(els.el);
38819 this.inner = Roo.get(els.inner, true);
38820 this.textEl = Roo.bootstrap.version == 4 ?
38821 this.el : Roo.get(this.el.dom.firstChild, true);
38823 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38824 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38827 // this.el.on("mousedown", this.onTabMouseDown, this);
38828 this.el.on("click", this.onTabClick, this);
38830 if(config.closable){
38831 var c = Roo.get(els.close, true);
38832 c.dom.title = this.closeText;
38833 c.addClassOnOver("close-over");
38834 c.on("click", this.closeClick, this);
38840 * Fires when this tab becomes the active tab.
38841 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38842 * @param {Roo.TabPanelItem} this
38846 * @event beforeclose
38847 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38848 * @param {Roo.TabPanelItem} this
38849 * @param {Object} e Set cancel to true on this object to cancel the close.
38851 "beforeclose": true,
38854 * Fires when this tab is closed.
38855 * @param {Roo.TabPanelItem} this
38859 * @event deactivate
38860 * Fires when this tab is no longer the active tab.
38861 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38862 * @param {Roo.TabPanelItem} this
38864 "deactivate" : true
38866 this.hidden = false;
38868 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38871 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38873 purgeListeners : function(){
38874 Roo.util.Observable.prototype.purgeListeners.call(this);
38875 this.el.removeAllListeners();
38878 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38881 this.status_node.addClass("active");
38884 this.tabPanel.stripWrap.repaint();
38886 this.fireEvent("activate", this.tabPanel, this);
38890 * Returns true if this tab is the active tab.
38891 * @return {Boolean}
38893 isActive : function(){
38894 return this.tabPanel.getActiveTab() == this;
38898 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38901 this.status_node.removeClass("active");
38903 this.fireEvent("deactivate", this.tabPanel, this);
38906 hideAction : function(){
38907 this.bodyEl.hide();
38908 this.bodyEl.setStyle("position", "absolute");
38909 this.bodyEl.setLeft("-20000px");
38910 this.bodyEl.setTop("-20000px");
38913 showAction : function(){
38914 this.bodyEl.setStyle("position", "relative");
38915 this.bodyEl.setTop("");
38916 this.bodyEl.setLeft("");
38917 this.bodyEl.show();
38921 * Set the tooltip for the tab.
38922 * @param {String} tooltip The tab's tooltip
38924 setTooltip : function(text){
38925 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38926 this.textEl.dom.qtip = text;
38927 this.textEl.dom.removeAttribute('title');
38929 this.textEl.dom.title = text;
38933 onTabClick : function(e){
38934 e.preventDefault();
38935 this.tabPanel.activate(this.id);
38938 onTabMouseDown : function(e){
38939 e.preventDefault();
38940 this.tabPanel.activate(this.id);
38943 getWidth : function(){
38944 return this.inner.getWidth();
38947 setWidth : function(width){
38948 var iwidth = width - this.linode.getPadding("lr");
38949 this.inner.setWidth(iwidth);
38950 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38951 this.linode.setWidth(width);
38955 * Show or hide the tab
38956 * @param {Boolean} hidden True to hide or false to show.
38958 setHidden : function(hidden){
38959 this.hidden = hidden;
38960 this.linode.setStyle("display", hidden ? "none" : "");
38964 * Returns true if this tab is "hidden"
38965 * @return {Boolean}
38967 isHidden : function(){
38968 return this.hidden;
38972 * Returns the text for this tab
38975 getText : function(){
38979 autoSize : function(){
38980 //this.el.beginMeasure();
38981 this.textEl.setWidth(1);
38983 * #2804 [new] Tabs in Roojs
38984 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38986 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38987 //this.el.endMeasure();
38991 * Sets the text for the tab (Note: this also sets the tooltip text)
38992 * @param {String} text The tab's text and tooltip
38994 setText : function(text){
38996 this.textEl.update(text);
38997 this.setTooltip(text);
38998 //if(!this.tabPanel.resizeTabs){
38999 // this.autoSize();
39003 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
39005 activate : function(){
39006 this.tabPanel.activate(this.id);
39010 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
39012 disable : function(){
39013 if(this.tabPanel.active != this){
39014 this.disabled = true;
39015 this.status_node.addClass("disabled");
39020 * Enables this TabPanelItem if it was previously disabled.
39022 enable : function(){
39023 this.disabled = false;
39024 this.status_node.removeClass("disabled");
39028 * Sets the content for this TabPanelItem.
39029 * @param {String} content The content
39030 * @param {Boolean} loadScripts true to look for and load scripts
39032 setContent : function(content, loadScripts){
39033 this.bodyEl.update(content, loadScripts);
39037 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
39038 * @return {Roo.UpdateManager} The UpdateManager
39040 getUpdateManager : function(){
39041 return this.bodyEl.getUpdateManager();
39045 * Set a URL to be used to load the content for this TabPanelItem.
39046 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
39047 * @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)
39048 * @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)
39049 * @return {Roo.UpdateManager} The UpdateManager
39051 setUrl : function(url, params, loadOnce){
39052 if(this.refreshDelegate){
39053 this.un('activate', this.refreshDelegate);
39055 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39056 this.on("activate", this.refreshDelegate);
39057 return this.bodyEl.getUpdateManager();
39061 _handleRefresh : function(url, params, loadOnce){
39062 if(!loadOnce || !this.loaded){
39063 var updater = this.bodyEl.getUpdateManager();
39064 updater.update(url, params, this._setLoaded.createDelegate(this));
39069 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39070 * Will fail silently if the setUrl method has not been called.
39071 * This does not activate the panel, just updates its content.
39073 refresh : function(){
39074 if(this.refreshDelegate){
39075 this.loaded = false;
39076 this.refreshDelegate();
39081 _setLoaded : function(){
39082 this.loaded = true;
39086 closeClick : function(e){
39089 this.fireEvent("beforeclose", this, o);
39090 if(o.cancel !== true){
39091 this.tabPanel.removeTab(this.id);
39095 * The text displayed in the tooltip for the close icon.
39098 closeText : "Close this tab"
39101 * This script refer to:
39102 * Title: International Telephone Input
39103 * Author: Jack O'Connor
39104 * Code version: v12.1.12
39105 * Availability: https://github.com/jackocnr/intl-tel-input.git
39108 Roo.bootstrap.PhoneInputData = function() {
39111 "Afghanistan (افغانستان)",
39116 "Albania (Shqipëri)",
39121 "Algeria (الجزائر)",
39146 "Antigua and Barbuda",
39156 "Armenia (Հայաստան)",
39172 "Austria (Österreich)",
39177 "Azerbaijan (Azərbaycan)",
39187 "Bahrain (البحرين)",
39192 "Bangladesh (বাংলাদেশ)",
39202 "Belarus (Беларусь)",
39207 "Belgium (België)",
39237 "Bosnia and Herzegovina (Босна и Херцеговина)",
39252 "British Indian Ocean Territory",
39257 "British Virgin Islands",
39267 "Bulgaria (България)",
39277 "Burundi (Uburundi)",
39282 "Cambodia (កម្ពុជា)",
39287 "Cameroon (Cameroun)",
39296 ["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"]
39299 "Cape Verde (Kabu Verdi)",
39304 "Caribbean Netherlands",
39315 "Central African Republic (République centrafricaine)",
39335 "Christmas Island",
39341 "Cocos (Keeling) Islands",
39352 "Comoros (جزر القمر)",
39357 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39362 "Congo (Republic) (Congo-Brazzaville)",
39382 "Croatia (Hrvatska)",
39403 "Czech Republic (Česká republika)",
39408 "Denmark (Danmark)",
39423 "Dominican Republic (República Dominicana)",
39427 ["809", "829", "849"]
39445 "Equatorial Guinea (Guinea Ecuatorial)",
39465 "Falkland Islands (Islas Malvinas)",
39470 "Faroe Islands (Føroyar)",
39491 "French Guiana (Guyane française)",
39496 "French Polynesia (Polynésie française)",
39511 "Georgia (საქართველო)",
39516 "Germany (Deutschland)",
39536 "Greenland (Kalaallit Nunaat)",
39573 "Guinea-Bissau (Guiné Bissau)",
39598 "Hungary (Magyarország)",
39603 "Iceland (Ísland)",
39623 "Iraq (العراق)",
39639 "Israel (ישראל)",
39666 "Jordan (الأردن)",
39671 "Kazakhstan (Казахстан)",
39692 "Kuwait (الكويت)",
39697 "Kyrgyzstan (Кыргызстан)",
39707 "Latvia (Latvija)",
39712 "Lebanon (لبنان)",
39727 "Libya (ليبيا)",
39737 "Lithuania (Lietuva)",
39752 "Macedonia (FYROM) (Македонија)",
39757 "Madagascar (Madagasikara)",
39787 "Marshall Islands",
39797 "Mauritania (موريتانيا)",
39802 "Mauritius (Moris)",
39823 "Moldova (Republica Moldova)",
39833 "Mongolia (Монгол)",
39838 "Montenegro (Crna Gora)",
39848 "Morocco (المغرب)",
39854 "Mozambique (Moçambique)",
39859 "Myanmar (Burma) (မြန်မာ)",
39864 "Namibia (Namibië)",
39879 "Netherlands (Nederland)",
39884 "New Caledonia (Nouvelle-Calédonie)",
39919 "North Korea (조선 민주주의 인민 공화국)",
39924 "Northern Mariana Islands",
39940 "Pakistan (پاکستان)",
39950 "Palestine (فلسطين)",
39960 "Papua New Guinea",
40002 "Réunion (La Réunion)",
40008 "Romania (România)",
40024 "Saint Barthélemy",
40035 "Saint Kitts and Nevis",
40045 "Saint Martin (Saint-Martin (partie française))",
40051 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
40056 "Saint Vincent and the Grenadines",
40071 "São Tomé and Príncipe (São Tomé e Príncipe)",
40076 "Saudi Arabia (المملكة العربية السعودية)",
40081 "Senegal (Sénégal)",
40111 "Slovakia (Slovensko)",
40116 "Slovenia (Slovenija)",
40126 "Somalia (Soomaaliya)",
40136 "South Korea (대한민국)",
40141 "South Sudan (جنوب السودان)",
40151 "Sri Lanka (ශ්රී ලංකාව)",
40156 "Sudan (السودان)",
40166 "Svalbard and Jan Mayen",
40177 "Sweden (Sverige)",
40182 "Switzerland (Schweiz)",
40187 "Syria (سوريا)",
40232 "Trinidad and Tobago",
40237 "Tunisia (تونس)",
40242 "Turkey (Türkiye)",
40252 "Turks and Caicos Islands",
40262 "U.S. Virgin Islands",
40272 "Ukraine (Україна)",
40277 "United Arab Emirates (الإمارات العربية المتحدة)",
40299 "Uzbekistan (Oʻzbekiston)",
40309 "Vatican City (Città del Vaticano)",
40320 "Vietnam (Việt Nam)",
40325 "Wallis and Futuna (Wallis-et-Futuna)",
40330 "Western Sahara (الصحراء الغربية)",
40336 "Yemen (اليمن)",
40360 * This script refer to:
40361 * Title: International Telephone Input
40362 * Author: Jack O'Connor
40363 * Code version: v12.1.12
40364 * Availability: https://github.com/jackocnr/intl-tel-input.git
40368 * @class Roo.bootstrap.PhoneInput
40369 * @extends Roo.bootstrap.TriggerField
40370 * An input with International dial-code selection
40372 * @cfg {String} defaultDialCode default '+852'
40373 * @cfg {Array} preferedCountries default []
40376 * Create a new PhoneInput.
40377 * @param {Object} config Configuration options
40380 Roo.bootstrap.PhoneInput = function(config) {
40381 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40384 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40386 listWidth: undefined,
40388 selectedClass: 'active',
40390 invalidClass : "has-warning",
40392 validClass: 'has-success',
40394 allowed: '0123456789',
40399 * @cfg {String} defaultDialCode The default dial code when initializing the input
40401 defaultDialCode: '+852',
40404 * @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
40406 preferedCountries: false,
40408 getAutoCreate : function()
40410 var data = Roo.bootstrap.PhoneInputData();
40411 var align = this.labelAlign || this.parentLabelAlign();
40414 this.allCountries = [];
40415 this.dialCodeMapping = [];
40417 for (var i = 0; i < data.length; i++) {
40419 this.allCountries[i] = {
40423 priority: c[3] || 0,
40424 areaCodes: c[4] || null
40426 this.dialCodeMapping[c[2]] = {
40429 priority: c[3] || 0,
40430 areaCodes: c[4] || null
40442 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40443 maxlength: this.max_length,
40444 cls : 'form-control tel-input',
40445 autocomplete: 'new-password'
40448 var hiddenInput = {
40451 cls: 'hidden-tel-input'
40455 hiddenInput.name = this.name;
40458 if (this.disabled) {
40459 input.disabled = true;
40462 var flag_container = {
40479 cls: this.hasFeedback ? 'has-feedback' : '',
40485 cls: 'dial-code-holder',
40492 cls: 'roo-select2-container input-group',
40499 if (this.fieldLabel.length) {
40502 tooltip: 'This field is required'
40508 cls: 'control-label',
40514 html: this.fieldLabel
40517 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40523 if(this.indicatorpos == 'right') {
40524 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40531 if(align == 'left') {
40539 if(this.labelWidth > 12){
40540 label.style = "width: " + this.labelWidth + 'px';
40542 if(this.labelWidth < 13 && this.labelmd == 0){
40543 this.labelmd = this.labelWidth;
40545 if(this.labellg > 0){
40546 label.cls += ' col-lg-' + this.labellg;
40547 input.cls += ' col-lg-' + (12 - this.labellg);
40549 if(this.labelmd > 0){
40550 label.cls += ' col-md-' + this.labelmd;
40551 container.cls += ' col-md-' + (12 - this.labelmd);
40553 if(this.labelsm > 0){
40554 label.cls += ' col-sm-' + this.labelsm;
40555 container.cls += ' col-sm-' + (12 - this.labelsm);
40557 if(this.labelxs > 0){
40558 label.cls += ' col-xs-' + this.labelxs;
40559 container.cls += ' col-xs-' + (12 - this.labelxs);
40569 var settings = this;
40571 ['xs','sm','md','lg'].map(function(size){
40572 if (settings[size]) {
40573 cfg.cls += ' col-' + size + '-' + settings[size];
40577 this.store = new Roo.data.Store({
40578 proxy : new Roo.data.MemoryProxy({}),
40579 reader : new Roo.data.JsonReader({
40590 'name' : 'dialCode',
40594 'name' : 'priority',
40598 'name' : 'areaCodes',
40605 if(!this.preferedCountries) {
40606 this.preferedCountries = [
40613 var p = this.preferedCountries.reverse();
40616 for (var i = 0; i < p.length; i++) {
40617 for (var j = 0; j < this.allCountries.length; j++) {
40618 if(this.allCountries[j].iso2 == p[i]) {
40619 var t = this.allCountries[j];
40620 this.allCountries.splice(j,1);
40621 this.allCountries.unshift(t);
40627 this.store.proxy.data = {
40629 data: this.allCountries
40635 initEvents : function()
40638 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40640 this.indicator = this.indicatorEl();
40641 this.flag = this.flagEl();
40642 this.dialCodeHolder = this.dialCodeHolderEl();
40644 this.trigger = this.el.select('div.flag-box',true).first();
40645 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40650 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40651 _this.list.setWidth(lw);
40654 this.list.on('mouseover', this.onViewOver, this);
40655 this.list.on('mousemove', this.onViewMove, this);
40656 this.inputEl().on("keyup", this.onKeyUp, this);
40657 this.inputEl().on("keypress", this.onKeyPress, this);
40659 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40661 this.view = new Roo.View(this.list, this.tpl, {
40662 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40665 this.view.on('click', this.onViewClick, this);
40666 this.setValue(this.defaultDialCode);
40669 onTriggerClick : function(e)
40671 Roo.log('trigger click');
40676 if(this.isExpanded()){
40678 this.hasFocus = false;
40680 this.store.load({});
40681 this.hasFocus = true;
40686 isExpanded : function()
40688 return this.list.isVisible();
40691 collapse : function()
40693 if(!this.isExpanded()){
40697 Roo.get(document).un('mousedown', this.collapseIf, this);
40698 Roo.get(document).un('mousewheel', this.collapseIf, this);
40699 this.fireEvent('collapse', this);
40703 expand : function()
40707 if(this.isExpanded() || !this.hasFocus){
40711 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40712 this.list.setWidth(lw);
40715 this.restrictHeight();
40717 Roo.get(document).on('mousedown', this.collapseIf, this);
40718 Roo.get(document).on('mousewheel', this.collapseIf, this);
40720 this.fireEvent('expand', this);
40723 restrictHeight : function()
40725 this.list.alignTo(this.inputEl(), this.listAlign);
40726 this.list.alignTo(this.inputEl(), this.listAlign);
40729 onViewOver : function(e, t)
40731 if(this.inKeyMode){
40734 var item = this.view.findItemFromChild(t);
40737 var index = this.view.indexOf(item);
40738 this.select(index, false);
40743 onViewClick : function(view, doFocus, el, e)
40745 var index = this.view.getSelectedIndexes()[0];
40747 var r = this.store.getAt(index);
40750 this.onSelect(r, index);
40752 if(doFocus !== false && !this.blockFocus){
40753 this.inputEl().focus();
40757 onViewMove : function(e, t)
40759 this.inKeyMode = false;
40762 select : function(index, scrollIntoView)
40764 this.selectedIndex = index;
40765 this.view.select(index);
40766 if(scrollIntoView !== false){
40767 var el = this.view.getNode(index);
40769 this.list.scrollChildIntoView(el, false);
40774 createList : function()
40776 this.list = Roo.get(document.body).createChild({
40778 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40779 style: 'display:none'
40782 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40785 collapseIf : function(e)
40787 var in_combo = e.within(this.el);
40788 var in_list = e.within(this.list);
40789 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40791 if (in_combo || in_list || is_list) {
40797 onSelect : function(record, index)
40799 if(this.fireEvent('beforeselect', this, record, index) !== false){
40801 this.setFlagClass(record.data.iso2);
40802 this.setDialCode(record.data.dialCode);
40803 this.hasFocus = false;
40805 this.fireEvent('select', this, record, index);
40809 flagEl : function()
40811 var flag = this.el.select('div.flag',true).first();
40818 dialCodeHolderEl : function()
40820 var d = this.el.select('input.dial-code-holder',true).first();
40827 setDialCode : function(v)
40829 this.dialCodeHolder.dom.value = '+'+v;
40832 setFlagClass : function(n)
40834 this.flag.dom.className = 'flag '+n;
40837 getValue : function()
40839 var v = this.inputEl().getValue();
40840 if(this.dialCodeHolder) {
40841 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40846 setValue : function(v)
40848 var d = this.getDialCode(v);
40850 //invalid dial code
40851 if(v.length == 0 || !d || d.length == 0) {
40853 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40854 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40860 this.setFlagClass(this.dialCodeMapping[d].iso2);
40861 this.setDialCode(d);
40862 this.inputEl().dom.value = v.replace('+'+d,'');
40863 this.hiddenEl().dom.value = this.getValue();
40868 getDialCode : function(v)
40872 if (v.length == 0) {
40873 return this.dialCodeHolder.dom.value;
40877 if (v.charAt(0) != "+") {
40880 var numericChars = "";
40881 for (var i = 1; i < v.length; i++) {
40882 var c = v.charAt(i);
40885 if (this.dialCodeMapping[numericChars]) {
40886 dialCode = v.substr(1, i);
40888 if (numericChars.length == 4) {
40898 this.setValue(this.defaultDialCode);
40902 hiddenEl : function()
40904 return this.el.select('input.hidden-tel-input',true).first();
40907 // after setting val
40908 onKeyUp : function(e){
40909 this.setValue(this.getValue());
40912 onKeyPress : function(e){
40913 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40920 * @class Roo.bootstrap.MoneyField
40921 * @extends Roo.bootstrap.ComboBox
40922 * Bootstrap MoneyField class
40925 * Create a new MoneyField.
40926 * @param {Object} config Configuration options
40929 Roo.bootstrap.MoneyField = function(config) {
40931 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40935 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40938 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40940 allowDecimals : true,
40942 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40944 decimalSeparator : ".",
40946 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40948 decimalPrecision : 0,
40950 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40952 allowNegative : true,
40954 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40958 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40960 minValue : Number.NEGATIVE_INFINITY,
40962 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40964 maxValue : Number.MAX_VALUE,
40966 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40968 minText : "The minimum value for this field is {0}",
40970 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40972 maxText : "The maximum value for this field is {0}",
40974 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40975 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40977 nanText : "{0} is not a valid number",
40979 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40983 * @cfg {String} defaults currency of the MoneyField
40984 * value should be in lkey
40986 defaultCurrency : false,
40988 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40990 thousandsDelimiter : false,
40992 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
41003 getAutoCreate : function()
41005 var align = this.labelAlign || this.parentLabelAlign();
41017 cls : 'form-control roo-money-amount-input',
41018 autocomplete: 'new-password'
41021 var hiddenInput = {
41025 cls: 'hidden-number-input'
41028 if(this.max_length) {
41029 input.maxlength = this.max_length;
41033 hiddenInput.name = this.name;
41036 if (this.disabled) {
41037 input.disabled = true;
41040 var clg = 12 - this.inputlg;
41041 var cmd = 12 - this.inputmd;
41042 var csm = 12 - this.inputsm;
41043 var cxs = 12 - this.inputxs;
41047 cls : 'row roo-money-field',
41051 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
41055 cls: 'roo-select2-container input-group',
41059 cls : 'form-control roo-money-currency-input',
41060 autocomplete: 'new-password',
41062 name : this.currencyName
41066 cls : 'input-group-addon',
41080 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41084 cls: this.hasFeedback ? 'has-feedback' : '',
41095 if (this.fieldLabel.length) {
41098 tooltip: 'This field is required'
41104 cls: 'control-label',
41110 html: this.fieldLabel
41113 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41119 if(this.indicatorpos == 'right') {
41120 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41127 if(align == 'left') {
41135 if(this.labelWidth > 12){
41136 label.style = "width: " + this.labelWidth + 'px';
41138 if(this.labelWidth < 13 && this.labelmd == 0){
41139 this.labelmd = this.labelWidth;
41141 if(this.labellg > 0){
41142 label.cls += ' col-lg-' + this.labellg;
41143 input.cls += ' col-lg-' + (12 - this.labellg);
41145 if(this.labelmd > 0){
41146 label.cls += ' col-md-' + this.labelmd;
41147 container.cls += ' col-md-' + (12 - this.labelmd);
41149 if(this.labelsm > 0){
41150 label.cls += ' col-sm-' + this.labelsm;
41151 container.cls += ' col-sm-' + (12 - this.labelsm);
41153 if(this.labelxs > 0){
41154 label.cls += ' col-xs-' + this.labelxs;
41155 container.cls += ' col-xs-' + (12 - this.labelxs);
41166 var settings = this;
41168 ['xs','sm','md','lg'].map(function(size){
41169 if (settings[size]) {
41170 cfg.cls += ' col-' + size + '-' + settings[size];
41177 initEvents : function()
41179 this.indicator = this.indicatorEl();
41181 this.initCurrencyEvent();
41183 this.initNumberEvent();
41186 initCurrencyEvent : function()
41189 throw "can not find store for combo";
41192 this.store = Roo.factory(this.store, Roo.data);
41193 this.store.parent = this;
41197 this.triggerEl = this.el.select('.input-group-addon', true).first();
41199 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41204 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41205 _this.list.setWidth(lw);
41208 this.list.on('mouseover', this.onViewOver, this);
41209 this.list.on('mousemove', this.onViewMove, this);
41210 this.list.on('scroll', this.onViewScroll, this);
41213 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41216 this.view = new Roo.View(this.list, this.tpl, {
41217 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41220 this.view.on('click', this.onViewClick, this);
41222 this.store.on('beforeload', this.onBeforeLoad, this);
41223 this.store.on('load', this.onLoad, this);
41224 this.store.on('loadexception', this.onLoadException, this);
41226 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41227 "up" : function(e){
41228 this.inKeyMode = true;
41232 "down" : function(e){
41233 if(!this.isExpanded()){
41234 this.onTriggerClick();
41236 this.inKeyMode = true;
41241 "enter" : function(e){
41244 if(this.fireEvent("specialkey", this, e)){
41245 this.onViewClick(false);
41251 "esc" : function(e){
41255 "tab" : function(e){
41258 if(this.fireEvent("specialkey", this, e)){
41259 this.onViewClick(false);
41267 doRelay : function(foo, bar, hname){
41268 if(hname == 'down' || this.scope.isExpanded()){
41269 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41277 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41281 initNumberEvent : function(e)
41283 this.inputEl().on("keydown" , this.fireKey, this);
41284 this.inputEl().on("focus", this.onFocus, this);
41285 this.inputEl().on("blur", this.onBlur, this);
41287 this.inputEl().relayEvent('keyup', this);
41289 if(this.indicator){
41290 this.indicator.addClass('invisible');
41293 this.originalValue = this.getValue();
41295 if(this.validationEvent == 'keyup'){
41296 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41297 this.inputEl().on('keyup', this.filterValidation, this);
41299 else if(this.validationEvent !== false){
41300 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41303 if(this.selectOnFocus){
41304 this.on("focus", this.preFocus, this);
41307 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41308 this.inputEl().on("keypress", this.filterKeys, this);
41310 this.inputEl().relayEvent('keypress', this);
41313 var allowed = "0123456789";
41315 if(this.allowDecimals){
41316 allowed += this.decimalSeparator;
41319 if(this.allowNegative){
41323 if(this.thousandsDelimiter) {
41327 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41329 var keyPress = function(e){
41331 var k = e.getKey();
41333 var c = e.getCharCode();
41336 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41337 allowed.indexOf(String.fromCharCode(c)) === -1
41343 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41347 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41352 this.inputEl().on("keypress", keyPress, this);
41356 onTriggerClick : function(e)
41363 this.loadNext = false;
41365 if(this.isExpanded()){
41370 this.hasFocus = true;
41372 if(this.triggerAction == 'all') {
41373 this.doQuery(this.allQuery, true);
41377 this.doQuery(this.getRawValue());
41380 getCurrency : function()
41382 var v = this.currencyEl().getValue();
41387 restrictHeight : function()
41389 this.list.alignTo(this.currencyEl(), this.listAlign);
41390 this.list.alignTo(this.currencyEl(), this.listAlign);
41393 onViewClick : function(view, doFocus, el, e)
41395 var index = this.view.getSelectedIndexes()[0];
41397 var r = this.store.getAt(index);
41400 this.onSelect(r, index);
41404 onSelect : function(record, index){
41406 if(this.fireEvent('beforeselect', this, record, index) !== false){
41408 this.setFromCurrencyData(index > -1 ? record.data : false);
41412 this.fireEvent('select', this, record, index);
41416 setFromCurrencyData : function(o)
41420 this.lastCurrency = o;
41422 if (this.currencyField) {
41423 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41425 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41428 this.lastSelectionText = currency;
41430 //setting default currency
41431 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41432 this.setCurrency(this.defaultCurrency);
41436 this.setCurrency(currency);
41439 setFromData : function(o)
41443 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41445 this.setFromCurrencyData(c);
41450 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41452 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41455 this.setValue(value);
41459 setCurrency : function(v)
41461 this.currencyValue = v;
41464 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41469 setValue : function(v)
41471 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41477 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41479 this.inputEl().dom.value = (v == '') ? '' :
41480 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41482 if(!this.allowZero && v === '0') {
41483 this.hiddenEl().dom.value = '';
41484 this.inputEl().dom.value = '';
41491 getRawValue : function()
41493 var v = this.inputEl().getValue();
41498 getValue : function()
41500 return this.fixPrecision(this.parseValue(this.getRawValue()));
41503 parseValue : function(value)
41505 if(this.thousandsDelimiter) {
41507 r = new RegExp(",", "g");
41508 value = value.replace(r, "");
41511 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41512 return isNaN(value) ? '' : value;
41516 fixPrecision : function(value)
41518 if(this.thousandsDelimiter) {
41520 r = new RegExp(",", "g");
41521 value = value.replace(r, "");
41524 var nan = isNaN(value);
41526 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41527 return nan ? '' : value;
41529 return parseFloat(value).toFixed(this.decimalPrecision);
41532 decimalPrecisionFcn : function(v)
41534 return Math.floor(v);
41537 validateValue : function(value)
41539 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41543 var num = this.parseValue(value);
41546 this.markInvalid(String.format(this.nanText, value));
41550 if(num < this.minValue){
41551 this.markInvalid(String.format(this.minText, this.minValue));
41555 if(num > this.maxValue){
41556 this.markInvalid(String.format(this.maxText, this.maxValue));
41563 validate : function()
41565 if(this.disabled || this.allowBlank){
41570 var currency = this.getCurrency();
41572 if(this.validateValue(this.getRawValue()) && currency.length){
41577 this.markInvalid();
41581 getName: function()
41586 beforeBlur : function()
41592 var v = this.parseValue(this.getRawValue());
41599 onBlur : function()
41603 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41604 //this.el.removeClass(this.focusClass);
41607 this.hasFocus = false;
41609 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41613 var v = this.getValue();
41615 if(String(v) !== String(this.startValue)){
41616 this.fireEvent('change', this, v, this.startValue);
41619 this.fireEvent("blur", this);
41622 inputEl : function()
41624 return this.el.select('.roo-money-amount-input', true).first();
41627 currencyEl : function()
41629 return this.el.select('.roo-money-currency-input', true).first();
41632 hiddenEl : function()
41634 return this.el.select('input.hidden-number-input',true).first();
41638 * @class Roo.bootstrap.BezierSignature
41639 * @extends Roo.bootstrap.Component
41640 * Bootstrap BezierSignature class
41641 * This script refer to:
41642 * Title: Signature Pad
41644 * Availability: https://github.com/szimek/signature_pad
41647 * Create a new BezierSignature
41648 * @param {Object} config The config object
41651 Roo.bootstrap.BezierSignature = function(config){
41652 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41658 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41665 mouse_btn_down: true,
41668 * @cfg {int} canvas height
41670 canvas_height: '200px',
41673 * @cfg {float|function} Radius of a single dot.
41678 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41683 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41688 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41693 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41698 * @cfg {string} Color used to clear the background. Can be any color format accepted by context.fillStyle. Defaults to "rgba(0,0,0,0)" (transparent black). Use a non-transparent color e.g. "rgb(255,255,255)" (opaque white) if you'd like to save signatures as JPEG images.
41700 bg_color: 'rgba(0, 0, 0, 0)',
41703 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41705 dot_color: 'black',
41708 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41710 velocity_filter_weight: 0.7,
41713 * @cfg {function} Callback when stroke begin.
41718 * @cfg {function} Callback when stroke end.
41722 getAutoCreate : function()
41724 var cls = 'roo-signature column';
41727 cls += ' ' + this.cls;
41737 for(var i = 0; i < col_sizes.length; i++) {
41738 if(this[col_sizes[i]]) {
41739 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41749 cls: 'roo-signature-body',
41753 cls: 'roo-signature-body-canvas',
41754 height: this.canvas_height,
41755 width: this.canvas_width
41762 style: 'display: none'
41770 initEvents: function()
41772 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41774 var canvas = this.canvasEl();
41776 // mouse && touch event swapping...
41777 canvas.dom.style.touchAction = 'none';
41778 canvas.dom.style.msTouchAction = 'none';
41780 this.mouse_btn_down = false;
41781 canvas.on('mousedown', this._handleMouseDown, this);
41782 canvas.on('mousemove', this._handleMouseMove, this);
41783 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41785 if (window.PointerEvent) {
41786 canvas.on('pointerdown', this._handleMouseDown, this);
41787 canvas.on('pointermove', this._handleMouseMove, this);
41788 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41791 if ('ontouchstart' in window) {
41792 canvas.on('touchstart', this._handleTouchStart, this);
41793 canvas.on('touchmove', this._handleTouchMove, this);
41794 canvas.on('touchend', this._handleTouchEnd, this);
41797 Roo.EventManager.onWindowResize(this.resize, this, true);
41799 // file input event
41800 this.fileEl().on('change', this.uploadImage, this);
41807 resize: function(){
41809 var canvas = this.canvasEl().dom;
41810 var ctx = this.canvasElCtx();
41811 var img_data = false;
41813 if(canvas.width > 0) {
41814 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41816 // setting canvas width will clean img data
41819 var style = window.getComputedStyle ?
41820 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41822 var padding_left = parseInt(style.paddingLeft) || 0;
41823 var padding_right = parseInt(style.paddingRight) || 0;
41825 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41828 ctx.putImageData(img_data, 0, 0);
41832 _handleMouseDown: function(e)
41834 if (e.browserEvent.which === 1) {
41835 this.mouse_btn_down = true;
41836 this.strokeBegin(e);
41840 _handleMouseMove: function (e)
41842 if (this.mouse_btn_down) {
41843 this.strokeMoveUpdate(e);
41847 _handleMouseUp: function (e)
41849 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41850 this.mouse_btn_down = false;
41855 _handleTouchStart: function (e) {
41857 e.preventDefault();
41858 if (e.browserEvent.targetTouches.length === 1) {
41859 // var touch = e.browserEvent.changedTouches[0];
41860 // this.strokeBegin(touch);
41862 this.strokeBegin(e); // assume e catching the correct xy...
41866 _handleTouchMove: function (e) {
41867 e.preventDefault();
41868 // var touch = event.targetTouches[0];
41869 // _this._strokeMoveUpdate(touch);
41870 this.strokeMoveUpdate(e);
41873 _handleTouchEnd: function (e) {
41874 var wasCanvasTouched = e.target === this.canvasEl().dom;
41875 if (wasCanvasTouched) {
41876 e.preventDefault();
41877 // var touch = event.changedTouches[0];
41878 // _this._strokeEnd(touch);
41883 reset: function () {
41884 this._lastPoints = [];
41885 this._lastVelocity = 0;
41886 this._lastWidth = (this.min_width + this.max_width) / 2;
41887 this.canvasElCtx().fillStyle = this.dot_color;
41890 strokeMoveUpdate: function(e)
41892 this.strokeUpdate(e);
41894 if (this.throttle) {
41895 this.throttleStroke(this.strokeUpdate, this.throttle);
41898 this.strokeUpdate(e);
41902 strokeBegin: function(e)
41904 var newPointGroup = {
41905 color: this.dot_color,
41909 if (typeof this.onBegin === 'function') {
41913 this.curve_data.push(newPointGroup);
41915 this.strokeUpdate(e);
41918 strokeUpdate: function(e)
41920 var rect = this.canvasEl().dom.getBoundingClientRect();
41921 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41922 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41923 var lastPoints = lastPointGroup.points;
41924 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41925 var isLastPointTooClose = lastPoint
41926 ? point.distanceTo(lastPoint) <= this.min_distance
41928 var color = lastPointGroup.color;
41929 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41930 var curve = this.addPoint(point);
41932 this.drawDot({color: color, point: point});
41935 this.drawCurve({color: color, curve: curve});
41945 strokeEnd: function(e)
41947 this.strokeUpdate(e);
41948 if (typeof this.onEnd === 'function') {
41953 addPoint: function (point) {
41954 var _lastPoints = this._lastPoints;
41955 _lastPoints.push(point);
41956 if (_lastPoints.length > 2) {
41957 if (_lastPoints.length === 3) {
41958 _lastPoints.unshift(_lastPoints[0]);
41960 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41961 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41962 _lastPoints.shift();
41968 calculateCurveWidths: function (startPoint, endPoint) {
41969 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41970 (1 - this.velocity_filter_weight) * this._lastVelocity;
41972 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41975 start: this._lastWidth
41978 this._lastVelocity = velocity;
41979 this._lastWidth = newWidth;
41983 drawDot: function (_a) {
41984 var color = _a.color, point = _a.point;
41985 var ctx = this.canvasElCtx();
41986 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41988 this.drawCurveSegment(point.x, point.y, width);
41990 ctx.fillStyle = color;
41994 drawCurve: function (_a) {
41995 var color = _a.color, curve = _a.curve;
41996 var ctx = this.canvasElCtx();
41997 var widthDelta = curve.endWidth - curve.startWidth;
41998 var drawSteps = Math.floor(curve.length()) * 2;
42000 ctx.fillStyle = color;
42001 for (var i = 0; i < drawSteps; i += 1) {
42002 var t = i / drawSteps;
42008 var x = uuu * curve.startPoint.x;
42009 x += 3 * uu * t * curve.control1.x;
42010 x += 3 * u * tt * curve.control2.x;
42011 x += ttt * curve.endPoint.x;
42012 var y = uuu * curve.startPoint.y;
42013 y += 3 * uu * t * curve.control1.y;
42014 y += 3 * u * tt * curve.control2.y;
42015 y += ttt * curve.endPoint.y;
42016 var width = curve.startWidth + ttt * widthDelta;
42017 this.drawCurveSegment(x, y, width);
42023 drawCurveSegment: function (x, y, width) {
42024 var ctx = this.canvasElCtx();
42026 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
42027 this.is_empty = false;
42032 var ctx = this.canvasElCtx();
42033 var canvas = this.canvasEl().dom;
42034 ctx.fillStyle = this.bg_color;
42035 ctx.clearRect(0, 0, canvas.width, canvas.height);
42036 ctx.fillRect(0, 0, canvas.width, canvas.height);
42037 this.curve_data = [];
42039 this.is_empty = true;
42044 return this.el.select('input',true).first();
42047 canvasEl: function()
42049 return this.el.select('canvas',true).first();
42052 canvasElCtx: function()
42054 return this.el.select('canvas',true).first().dom.getContext('2d');
42057 getImage: function(type)
42059 if(this.is_empty) {
42064 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42067 drawFromImage: function(img_src)
42069 var img = new Image();
42071 img.onload = function(){
42072 this.canvasElCtx().drawImage(img, 0, 0);
42077 this.is_empty = false;
42080 selectImage: function()
42082 this.fileEl().dom.click();
42085 uploadImage: function(e)
42087 var reader = new FileReader();
42089 reader.onload = function(e){
42090 var img = new Image();
42091 img.onload = function(){
42093 this.canvasElCtx().drawImage(img, 0, 0);
42095 img.src = e.target.result;
42098 reader.readAsDataURL(e.target.files[0]);
42101 // Bezier Point Constructor
42102 Point: (function () {
42103 function Point(x, y, time) {
42106 this.time = time || Date.now();
42108 Point.prototype.distanceTo = function (start) {
42109 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42111 Point.prototype.equals = function (other) {
42112 return this.x === other.x && this.y === other.y && this.time === other.time;
42114 Point.prototype.velocityFrom = function (start) {
42115 return this.time !== start.time
42116 ? this.distanceTo(start) / (this.time - start.time)
42123 // Bezier Constructor
42124 Bezier: (function () {
42125 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42126 this.startPoint = startPoint;
42127 this.control2 = control2;
42128 this.control1 = control1;
42129 this.endPoint = endPoint;
42130 this.startWidth = startWidth;
42131 this.endWidth = endWidth;
42133 Bezier.fromPoints = function (points, widths, scope) {
42134 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42135 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42136 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42138 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42139 var dx1 = s1.x - s2.x;
42140 var dy1 = s1.y - s2.y;
42141 var dx2 = s2.x - s3.x;
42142 var dy2 = s2.y - s3.y;
42143 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42144 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42145 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42146 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42147 var dxm = m1.x - m2.x;
42148 var dym = m1.y - m2.y;
42149 var k = l2 / (l1 + l2);
42150 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42151 var tx = s2.x - cm.x;
42152 var ty = s2.y - cm.y;
42154 c1: new scope.Point(m1.x + tx, m1.y + ty),
42155 c2: new scope.Point(m2.x + tx, m2.y + ty)
42158 Bezier.prototype.length = function () {
42163 for (var i = 0; i <= steps; i += 1) {
42165 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42166 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42168 var xdiff = cx - px;
42169 var ydiff = cy - py;
42170 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42177 Bezier.prototype.point = function (t, start, c1, c2, end) {
42178 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42179 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42180 + (3.0 * c2 * (1.0 - t) * t * t)
42181 + (end * t * t * t);
42186 throttleStroke: function(fn, wait) {
42187 if (wait === void 0) { wait = 250; }
42189 var timeout = null;
42193 var later = function () {
42194 previous = Date.now();
42196 result = fn.apply(storedContext, storedArgs);
42198 storedContext = null;
42202 return function wrapper() {
42204 for (var _i = 0; _i < arguments.length; _i++) {
42205 args[_i] = arguments[_i];
42207 var now = Date.now();
42208 var remaining = wait - (now - previous);
42209 storedContext = this;
42211 if (remaining <= 0 || remaining > wait) {
42213 clearTimeout(timeout);
42217 result = fn.apply(storedContext, storedArgs);
42219 storedContext = null;
42223 else if (!timeout) {
42224 timeout = window.setTimeout(later, remaining);