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 {Object} an existing reader (eg. copied from another store)
12133 * @cfg {Array} data The multi-dimensional array of data
12135 * @param {Object} config
12137 Roo.data.SimpleStore = function(config)
12139 Roo.data.SimpleStore.superclass.constructor.call(this, {
12141 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
12144 Roo.data.Record.create(config.fields)
12146 proxy : new Roo.data.MemoryProxy(config.data)
12150 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12152 * Ext JS Library 1.1.1
12153 * Copyright(c) 2006-2007, Ext JS, LLC.
12155 * Originally Released Under LGPL - original licence link has changed is not relivant.
12158 * <script type="text/javascript">
12163 * @extends Roo.data.Store
12164 * @class Roo.data.JsonStore
12165 * Small helper class to make creating Stores for JSON data easier. <br/>
12167 var store = new Roo.data.JsonStore({
12168 url: 'get-images.php',
12170 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12173 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12174 * JsonReader and HttpProxy (unless inline data is provided).</b>
12175 * @cfg {Array} fields An array of field definition objects, or field name strings.
12177 * @param {Object} config
12179 Roo.data.JsonStore = function(c){
12180 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12181 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12182 reader: new Roo.data.JsonReader(c, c.fields)
12185 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12187 * Ext JS Library 1.1.1
12188 * Copyright(c) 2006-2007, Ext JS, LLC.
12190 * Originally Released Under LGPL - original licence link has changed is not relivant.
12193 * <script type="text/javascript">
12197 Roo.data.Field = function(config){
12198 if(typeof config == "string"){
12199 config = {name: config};
12201 Roo.apply(this, config);
12204 this.type = "auto";
12207 var st = Roo.data.SortTypes;
12208 // named sortTypes are supported, here we look them up
12209 if(typeof this.sortType == "string"){
12210 this.sortType = st[this.sortType];
12213 // set default sortType for strings and dates
12214 if(!this.sortType){
12217 this.sortType = st.asUCString;
12220 this.sortType = st.asDate;
12223 this.sortType = st.none;
12228 var stripRe = /[\$,%]/g;
12230 // prebuilt conversion function for this field, instead of
12231 // switching every time we're reading a value
12233 var cv, dateFormat = this.dateFormat;
12238 cv = function(v){ return v; };
12241 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12245 return v !== undefined && v !== null && v !== '' ?
12246 parseInt(String(v).replace(stripRe, ""), 10) : '';
12251 return v !== undefined && v !== null && v !== '' ?
12252 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12257 cv = function(v){ return v === true || v === "true" || v == 1; };
12264 if(v instanceof Date){
12268 if(dateFormat == "timestamp"){
12269 return new Date(v*1000);
12271 return Date.parseDate(v, dateFormat);
12273 var parsed = Date.parse(v);
12274 return parsed ? new Date(parsed) : null;
12283 Roo.data.Field.prototype = {
12291 * Ext JS Library 1.1.1
12292 * Copyright(c) 2006-2007, Ext JS, LLC.
12294 * Originally Released Under LGPL - original licence link has changed is not relivant.
12297 * <script type="text/javascript">
12300 // Base class for reading structured data from a data source. This class is intended to be
12301 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12304 * @class Roo.data.DataReader
12305 * Base class for reading structured data from a data source. This class is intended to be
12306 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12309 Roo.data.DataReader = function(meta, recordType){
12313 this.recordType = recordType instanceof Array ?
12314 Roo.data.Record.create(recordType) : recordType;
12317 Roo.data.DataReader.prototype = {
12320 readerType : 'Data',
12322 * Create an empty record
12323 * @param {Object} data (optional) - overlay some values
12324 * @return {Roo.data.Record} record created.
12326 newRow : function(d) {
12328 this.recordType.prototype.fields.each(function(c) {
12330 case 'int' : da[c.name] = 0; break;
12331 case 'date' : da[c.name] = new Date(); break;
12332 case 'float' : da[c.name] = 0.0; break;
12333 case 'boolean' : da[c.name] = false; break;
12334 default : da[c.name] = ""; break;
12338 return new this.recordType(Roo.apply(da, d));
12344 * Ext JS Library 1.1.1
12345 * Copyright(c) 2006-2007, Ext JS, LLC.
12347 * Originally Released Under LGPL - original licence link has changed is not relivant.
12350 * <script type="text/javascript">
12354 * @class Roo.data.DataProxy
12355 * @extends Roo.data.Observable
12356 * This class is an abstract base class for implementations which provide retrieval of
12357 * unformatted data objects.<br>
12359 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12360 * (of the appropriate type which knows how to parse the data object) to provide a block of
12361 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12363 * Custom implementations must implement the load method as described in
12364 * {@link Roo.data.HttpProxy#load}.
12366 Roo.data.DataProxy = function(){
12369 * @event beforeload
12370 * Fires before a network request is made to retrieve a data object.
12371 * @param {Object} This DataProxy object.
12372 * @param {Object} params The params parameter to the load function.
12377 * Fires before the load method's callback is called.
12378 * @param {Object} This DataProxy object.
12379 * @param {Object} o The data object.
12380 * @param {Object} arg The callback argument object passed to the load function.
12384 * @event loadexception
12385 * Fires if an Exception occurs during data retrieval.
12386 * @param {Object} This DataProxy object.
12387 * @param {Object} o The data object.
12388 * @param {Object} arg The callback argument object passed to the load function.
12389 * @param {Object} e The Exception.
12391 loadexception : true
12393 Roo.data.DataProxy.superclass.constructor.call(this);
12396 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12399 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12403 * Ext JS Library 1.1.1
12404 * Copyright(c) 2006-2007, Ext JS, LLC.
12406 * Originally Released Under LGPL - original licence link has changed is not relivant.
12409 * <script type="text/javascript">
12412 * @class Roo.data.MemoryProxy
12413 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12414 * to the Reader when its load method is called.
12416 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12418 Roo.data.MemoryProxy = function(data){
12422 Roo.data.MemoryProxy.superclass.constructor.call(this);
12426 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12429 * Load data from the requested source (in this case an in-memory
12430 * data object passed to the constructor), read the data object into
12431 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12432 * process that block using the passed callback.
12433 * @param {Object} params This parameter is not used by the MemoryProxy class.
12434 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12435 * object into a block of Roo.data.Records.
12436 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12437 * The function must be passed <ul>
12438 * <li>The Record block object</li>
12439 * <li>The "arg" argument from the load function</li>
12440 * <li>A boolean success indicator</li>
12442 * @param {Object} scope The scope in which to call the callback
12443 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12445 load : function(params, reader, callback, scope, arg){
12446 params = params || {};
12449 result = reader.readRecords(params.data ? params.data :this.data);
12451 this.fireEvent("loadexception", this, arg, null, e);
12452 callback.call(scope, null, arg, false);
12455 callback.call(scope, result, arg, true);
12459 update : function(params, records){
12464 * Ext JS Library 1.1.1
12465 * Copyright(c) 2006-2007, Ext JS, LLC.
12467 * Originally Released Under LGPL - original licence link has changed is not relivant.
12470 * <script type="text/javascript">
12473 * @class Roo.data.HttpProxy
12474 * @extends Roo.data.DataProxy
12475 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12476 * configured to reference a certain URL.<br><br>
12478 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12479 * from which the running page was served.<br><br>
12481 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12483 * Be aware that to enable the browser to parse an XML document, the server must set
12484 * the Content-Type header in the HTTP response to "text/xml".
12486 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12487 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12488 * will be used to make the request.
12490 Roo.data.HttpProxy = function(conn){
12491 Roo.data.HttpProxy.superclass.constructor.call(this);
12492 // is conn a conn config or a real conn?
12494 this.useAjax = !conn || !conn.events;
12498 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12499 // thse are take from connection...
12502 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12505 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12506 * extra parameters to each request made by this object. (defaults to undefined)
12509 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12510 * to each request made by this object. (defaults to undefined)
12513 * @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)
12516 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12519 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12525 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12529 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12530 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12531 * a finer-grained basis than the DataProxy events.
12533 getConnection : function(){
12534 return this.useAjax ? Roo.Ajax : this.conn;
12538 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12539 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12540 * process that block using the passed callback.
12541 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12542 * for the request to the remote server.
12543 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12544 * object into a block of Roo.data.Records.
12545 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12546 * The function must be passed <ul>
12547 * <li>The Record block object</li>
12548 * <li>The "arg" argument from the load function</li>
12549 * <li>A boolean success indicator</li>
12551 * @param {Object} scope The scope in which to call the callback
12552 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12554 load : function(params, reader, callback, scope, arg){
12555 if(this.fireEvent("beforeload", this, params) !== false){
12557 params : params || {},
12559 callback : callback,
12564 callback : this.loadResponse,
12568 Roo.applyIf(o, this.conn);
12569 if(this.activeRequest){
12570 Roo.Ajax.abort(this.activeRequest);
12572 this.activeRequest = Roo.Ajax.request(o);
12574 this.conn.request(o);
12577 callback.call(scope||this, null, arg, false);
12582 loadResponse : function(o, success, response){
12583 delete this.activeRequest;
12585 this.fireEvent("loadexception", this, o, response);
12586 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12591 result = o.reader.read(response);
12593 this.fireEvent("loadexception", this, o, response, e);
12594 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12598 this.fireEvent("load", this, o, o.request.arg);
12599 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12603 update : function(dataSet){
12608 updateResponse : function(dataSet){
12613 * Ext JS Library 1.1.1
12614 * Copyright(c) 2006-2007, Ext JS, LLC.
12616 * Originally Released Under LGPL - original licence link has changed is not relivant.
12619 * <script type="text/javascript">
12623 * @class Roo.data.ScriptTagProxy
12624 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12625 * other than the originating domain of the running page.<br><br>
12627 * <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
12628 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12630 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12631 * source code that is used as the source inside a <script> tag.<br><br>
12633 * In order for the browser to process the returned data, the server must wrap the data object
12634 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12635 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12636 * depending on whether the callback name was passed:
12639 boolean scriptTag = false;
12640 String cb = request.getParameter("callback");
12643 response.setContentType("text/javascript");
12645 response.setContentType("application/x-json");
12647 Writer out = response.getWriter();
12649 out.write(cb + "(");
12651 out.print(dataBlock.toJsonString());
12658 * @param {Object} config A configuration object.
12660 Roo.data.ScriptTagProxy = function(config){
12661 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12662 Roo.apply(this, config);
12663 this.head = document.getElementsByTagName("head")[0];
12666 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12668 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12670 * @cfg {String} url The URL from which to request the data object.
12673 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12677 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12678 * the server the name of the callback function set up by the load call to process the returned data object.
12679 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12680 * javascript output which calls this named function passing the data object as its only parameter.
12682 callbackParam : "callback",
12684 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12685 * name to the request.
12690 * Load data from the configured URL, read the data object into
12691 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12692 * process that block using the passed callback.
12693 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12694 * for the request to the remote server.
12695 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12696 * object into a block of Roo.data.Records.
12697 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12698 * The function must be passed <ul>
12699 * <li>The Record block object</li>
12700 * <li>The "arg" argument from the load function</li>
12701 * <li>A boolean success indicator</li>
12703 * @param {Object} scope The scope in which to call the callback
12704 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12706 load : function(params, reader, callback, scope, arg){
12707 if(this.fireEvent("beforeload", this, params) !== false){
12709 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12711 var url = this.url;
12712 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12714 url += "&_dc=" + (new Date().getTime());
12716 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12719 cb : "stcCallback"+transId,
12720 scriptId : "stcScript"+transId,
12724 callback : callback,
12730 window[trans.cb] = function(o){
12731 conn.handleResponse(o, trans);
12734 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12736 if(this.autoAbort !== false){
12740 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12742 var script = document.createElement("script");
12743 script.setAttribute("src", url);
12744 script.setAttribute("type", "text/javascript");
12745 script.setAttribute("id", trans.scriptId);
12746 this.head.appendChild(script);
12748 this.trans = trans;
12750 callback.call(scope||this, null, arg, false);
12755 isLoading : function(){
12756 return this.trans ? true : false;
12760 * Abort the current server request.
12762 abort : function(){
12763 if(this.isLoading()){
12764 this.destroyTrans(this.trans);
12769 destroyTrans : function(trans, isLoaded){
12770 this.head.removeChild(document.getElementById(trans.scriptId));
12771 clearTimeout(trans.timeoutId);
12773 window[trans.cb] = undefined;
12775 delete window[trans.cb];
12778 // if hasn't been loaded, wait for load to remove it to prevent script error
12779 window[trans.cb] = function(){
12780 window[trans.cb] = undefined;
12782 delete window[trans.cb];
12789 handleResponse : function(o, trans){
12790 this.trans = false;
12791 this.destroyTrans(trans, true);
12794 result = trans.reader.readRecords(o);
12796 this.fireEvent("loadexception", this, o, trans.arg, e);
12797 trans.callback.call(trans.scope||window, null, trans.arg, false);
12800 this.fireEvent("load", this, o, trans.arg);
12801 trans.callback.call(trans.scope||window, result, trans.arg, true);
12805 handleFailure : function(trans){
12806 this.trans = false;
12807 this.destroyTrans(trans, false);
12808 this.fireEvent("loadexception", this, null, trans.arg);
12809 trans.callback.call(trans.scope||window, null, trans.arg, false);
12813 * Ext JS Library 1.1.1
12814 * Copyright(c) 2006-2007, Ext JS, LLC.
12816 * Originally Released Under LGPL - original licence link has changed is not relivant.
12819 * <script type="text/javascript">
12823 * @class Roo.data.JsonReader
12824 * @extends Roo.data.DataReader
12825 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12826 * based on mappings in a provided Roo.data.Record constructor.
12828 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12829 * in the reply previously.
12834 var RecordDef = Roo.data.Record.create([
12835 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12836 {name: 'occupation'} // This field will use "occupation" as the mapping.
12838 var myReader = new Roo.data.JsonReader({
12839 totalProperty: "results", // The property which contains the total dataset size (optional)
12840 root: "rows", // The property which contains an Array of row objects
12841 id: "id" // The property within each row object that provides an ID for the record (optional)
12845 * This would consume a JSON file like this:
12847 { 'results': 2, 'rows': [
12848 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12849 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12852 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12853 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12854 * paged from the remote server.
12855 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12856 * @cfg {String} root name of the property which contains the Array of row objects.
12857 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12858 * @cfg {Array} fields Array of field definition objects
12860 * Create a new JsonReader
12861 * @param {Object} meta Metadata configuration options
12862 * @param {Object} recordType Either an Array of field definition objects,
12863 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12865 Roo.data.JsonReader = function(meta, recordType){
12868 // set some defaults:
12869 Roo.applyIf(meta, {
12870 totalProperty: 'total',
12871 successProperty : 'success',
12876 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12878 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12880 readerType : 'Json',
12883 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12884 * Used by Store query builder to append _requestMeta to params.
12887 metaFromRemote : false,
12889 * This method is only used by a DataProxy which has retrieved data from a remote server.
12890 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12891 * @return {Object} data A data block which is used by an Roo.data.Store object as
12892 * a cache of Roo.data.Records.
12894 read : function(response){
12895 var json = response.responseText;
12897 var o = /* eval:var:o */ eval("("+json+")");
12899 throw {message: "JsonReader.read: Json object not found"};
12905 this.metaFromRemote = true;
12906 this.meta = o.metaData;
12907 this.recordType = Roo.data.Record.create(o.metaData.fields);
12908 this.onMetaChange(this.meta, this.recordType, o);
12910 return this.readRecords(o);
12913 // private function a store will implement
12914 onMetaChange : function(meta, recordType, o){
12921 simpleAccess: function(obj, subsc) {
12928 getJsonAccessor: function(){
12930 return function(expr) {
12932 return(re.test(expr))
12933 ? new Function("obj", "return obj." + expr)
12938 return Roo.emptyFn;
12943 * Create a data block containing Roo.data.Records from an XML document.
12944 * @param {Object} o An object which contains an Array of row objects in the property specified
12945 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12946 * which contains the total size of the dataset.
12947 * @return {Object} data A data block which is used by an Roo.data.Store object as
12948 * a cache of Roo.data.Records.
12950 readRecords : function(o){
12952 * After any data loads, the raw JSON data is available for further custom processing.
12956 var s = this.meta, Record = this.recordType,
12957 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12959 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12961 if(s.totalProperty) {
12962 this.getTotal = this.getJsonAccessor(s.totalProperty);
12964 if(s.successProperty) {
12965 this.getSuccess = this.getJsonAccessor(s.successProperty);
12967 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12969 var g = this.getJsonAccessor(s.id);
12970 this.getId = function(rec) {
12972 return (r === undefined || r === "") ? null : r;
12975 this.getId = function(){return null;};
12978 for(var jj = 0; jj < fl; jj++){
12980 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12981 this.ef[jj] = this.getJsonAccessor(map);
12985 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12986 if(s.totalProperty){
12987 var vt = parseInt(this.getTotal(o), 10);
12992 if(s.successProperty){
12993 var vs = this.getSuccess(o);
12994 if(vs === false || vs === 'false'){
12999 for(var i = 0; i < c; i++){
13002 var id = this.getId(n);
13003 for(var j = 0; j < fl; j++){
13005 var v = this.ef[j](n);
13007 Roo.log('missing convert for ' + f.name);
13011 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13013 var record = new Record(values, id);
13015 records[i] = record;
13021 totalRecords : totalRecords
13026 * Ext JS Library 1.1.1
13027 * Copyright(c) 2006-2007, Ext JS, LLC.
13029 * Originally Released Under LGPL - original licence link has changed is not relivant.
13032 * <script type="text/javascript">
13036 * @class Roo.data.ArrayReader
13037 * @extends Roo.data.DataReader
13038 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13039 * Each element of that Array represents a row of data fields. The
13040 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13041 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13045 var RecordDef = Roo.data.Record.create([
13046 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13047 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13049 var myReader = new Roo.data.ArrayReader({
13050 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13054 * This would consume an Array like this:
13056 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13060 * Create a new JsonReader
13061 * @param {Object} meta Metadata configuration options.
13062 * @param {Object|Array} recordType Either an Array of field definition objects
13064 * @cfg {Array} fields Array of field definition objects
13065 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13066 * as specified to {@link Roo.data.Record#create},
13067 * or an {@link Roo.data.Record} object
13070 * created using {@link Roo.data.Record#create}.
13072 Roo.data.ArrayReader = function(meta, recordType)
13074 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13077 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13079 readerType : 'Array',
13081 * Create a data block containing Roo.data.Records from an XML document.
13082 * @param {Object} o An Array of row objects which represents the dataset.
13083 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13084 * a cache of Roo.data.Records.
13086 readRecords : function(o)
13088 var sid = this.meta ? this.meta.id : null;
13089 var recordType = this.recordType, fields = recordType.prototype.fields;
13092 for(var i = 0; i < root.length; i++){
13095 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13096 for(var j = 0, jlen = fields.length; j < jlen; j++){
13097 var f = fields.items[j];
13098 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13099 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13101 values[f.name] = v;
13103 var record = new recordType(values, id);
13105 records[records.length] = record;
13109 totalRecords : records.length
13118 * @class Roo.bootstrap.ComboBox
13119 * @extends Roo.bootstrap.TriggerField
13120 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13121 * @cfg {Boolean} append (true|false) default false
13122 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13123 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13124 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13125 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13126 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13127 * @cfg {Boolean} animate default true
13128 * @cfg {Boolean} emptyResultText only for touch device
13129 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13130 * @cfg {String} emptyTitle default ''
13132 * Create a new ComboBox.
13133 * @param {Object} config Configuration options
13135 Roo.bootstrap.ComboBox = function(config){
13136 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13140 * Fires when the dropdown list is expanded
13141 * @param {Roo.bootstrap.ComboBox} combo This combo box
13146 * Fires when the dropdown list is collapsed
13147 * @param {Roo.bootstrap.ComboBox} combo This combo box
13151 * @event beforeselect
13152 * Fires before a list item is selected. Return false to cancel the selection.
13153 * @param {Roo.bootstrap.ComboBox} combo This combo box
13154 * @param {Roo.data.Record} record The data record returned from the underlying store
13155 * @param {Number} index The index of the selected item in the dropdown list
13157 'beforeselect' : true,
13160 * Fires when a list item is selected
13161 * @param {Roo.bootstrap.ComboBox} combo This combo box
13162 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13163 * @param {Number} index The index of the selected item in the dropdown list
13167 * @event beforequery
13168 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13169 * The event object passed has these properties:
13170 * @param {Roo.bootstrap.ComboBox} combo This combo box
13171 * @param {String} query The query
13172 * @param {Boolean} forceAll true to force "all" query
13173 * @param {Boolean} cancel true to cancel the query
13174 * @param {Object} e The query event object
13176 'beforequery': true,
13179 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13180 * @param {Roo.bootstrap.ComboBox} combo This combo box
13185 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13186 * @param {Roo.bootstrap.ComboBox} combo This combo box
13187 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13192 * Fires when the remove value from the combobox array
13193 * @param {Roo.bootstrap.ComboBox} combo This combo box
13197 * @event afterremove
13198 * Fires when the remove value from the combobox array
13199 * @param {Roo.bootstrap.ComboBox} combo This combo box
13201 'afterremove' : true,
13203 * @event specialfilter
13204 * Fires when specialfilter
13205 * @param {Roo.bootstrap.ComboBox} combo This combo box
13207 'specialfilter' : true,
13210 * Fires when tick the element
13211 * @param {Roo.bootstrap.ComboBox} combo This combo box
13215 * @event touchviewdisplay
13216 * Fires when touch view require special display (default is using displayField)
13217 * @param {Roo.bootstrap.ComboBox} combo This combo box
13218 * @param {Object} cfg set html .
13220 'touchviewdisplay' : true
13225 this.tickItems = [];
13227 this.selectedIndex = -1;
13228 if(this.mode == 'local'){
13229 if(config.queryDelay === undefined){
13230 this.queryDelay = 10;
13232 if(config.minChars === undefined){
13238 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13241 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13242 * rendering into an Roo.Editor, defaults to false)
13245 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13246 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13249 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13252 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13253 * the dropdown list (defaults to undefined, with no header element)
13257 * @cfg {String/Roo.Template} tpl The template to use to render the output
13261 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13263 listWidth: undefined,
13265 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13266 * mode = 'remote' or 'text' if mode = 'local')
13268 displayField: undefined,
13271 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13272 * mode = 'remote' or 'value' if mode = 'local').
13273 * Note: use of a valueField requires the user make a selection
13274 * in order for a value to be mapped.
13276 valueField: undefined,
13278 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13283 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13284 * field's data value (defaults to the underlying DOM element's name)
13286 hiddenName: undefined,
13288 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13292 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13294 selectedClass: 'active',
13297 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13301 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13302 * anchor positions (defaults to 'tl-bl')
13304 listAlign: 'tl-bl?',
13306 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13310 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13311 * query specified by the allQuery config option (defaults to 'query')
13313 triggerAction: 'query',
13315 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13316 * (defaults to 4, does not apply if editable = false)
13320 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13321 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13325 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13326 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13330 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13331 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13335 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13336 * when editable = true (defaults to false)
13338 selectOnFocus:false,
13340 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13342 queryParam: 'query',
13344 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13345 * when mode = 'remote' (defaults to 'Loading...')
13347 loadingText: 'Loading...',
13349 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13353 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13357 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13358 * traditional select (defaults to true)
13362 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13366 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13370 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13371 * listWidth has a higher value)
13375 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13376 * allow the user to set arbitrary text into the field (defaults to false)
13378 forceSelection:false,
13380 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13381 * if typeAhead = true (defaults to 250)
13383 typeAheadDelay : 250,
13385 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13386 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13388 valueNotFoundText : undefined,
13390 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13392 blockFocus : false,
13395 * @cfg {Boolean} disableClear Disable showing of clear button.
13397 disableClear : false,
13399 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13401 alwaysQuery : false,
13404 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13409 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13411 invalidClass : "has-warning",
13414 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13416 validClass : "has-success",
13419 * @cfg {Boolean} specialFilter (true|false) special filter default false
13421 specialFilter : false,
13424 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13426 mobileTouchView : true,
13429 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13431 useNativeIOS : false,
13434 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13436 mobile_restrict_height : false,
13438 ios_options : false,
13450 btnPosition : 'right',
13451 triggerList : true,
13452 showToggleBtn : true,
13454 emptyResultText: 'Empty',
13455 triggerText : 'Select',
13458 // element that contains real text value.. (when hidden is used..)
13460 getAutoCreate : function()
13465 * Render classic select for iso
13468 if(Roo.isIOS && this.useNativeIOS){
13469 cfg = this.getAutoCreateNativeIOS();
13477 if(Roo.isTouch && this.mobileTouchView){
13478 cfg = this.getAutoCreateTouchView();
13485 if(!this.tickable){
13486 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13491 * ComboBox with tickable selections
13494 var align = this.labelAlign || this.parentLabelAlign();
13497 cls : 'form-group roo-combobox-tickable' //input-group
13500 var btn_text_select = '';
13501 var btn_text_done = '';
13502 var btn_text_cancel = '';
13504 if (this.btn_text_show) {
13505 btn_text_select = 'Select';
13506 btn_text_done = 'Done';
13507 btn_text_cancel = 'Cancel';
13512 cls : 'tickable-buttons',
13517 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13518 //html : this.triggerText
13519 html: btn_text_select
13525 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13527 html: btn_text_done
13533 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13535 html: btn_text_cancel
13541 buttons.cn.unshift({
13543 cls: 'roo-select2-search-field-input'
13549 Roo.each(buttons.cn, function(c){
13551 c.cls += ' btn-' + _this.size;
13554 if (_this.disabled) {
13561 style : 'display: contents',
13566 cls: 'form-hidden-field'
13570 cls: 'roo-select2-choices',
13574 cls: 'roo-select2-search-field',
13585 cls: 'roo-select2-container input-group roo-select2-container-multi',
13591 // cls: 'typeahead typeahead-long dropdown-menu',
13592 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13597 if(this.hasFeedback && !this.allowBlank){
13601 cls: 'glyphicon form-control-feedback'
13604 combobox.cn.push(feedback);
13609 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13610 tooltip : 'This field is required'
13612 if (Roo.bootstrap.version == 4) {
13615 style : 'display:none'
13618 if (align ==='left' && this.fieldLabel.length) {
13620 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13627 cls : 'control-label col-form-label',
13628 html : this.fieldLabel
13640 var labelCfg = cfg.cn[1];
13641 var contentCfg = cfg.cn[2];
13644 if(this.indicatorpos == 'right'){
13650 cls : 'control-label col-form-label',
13654 html : this.fieldLabel
13670 labelCfg = cfg.cn[0];
13671 contentCfg = cfg.cn[1];
13675 if(this.labelWidth > 12){
13676 labelCfg.style = "width: " + this.labelWidth + 'px';
13679 if(this.labelWidth < 13 && this.labelmd == 0){
13680 this.labelmd = this.labelWidth;
13683 if(this.labellg > 0){
13684 labelCfg.cls += ' col-lg-' + this.labellg;
13685 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13688 if(this.labelmd > 0){
13689 labelCfg.cls += ' col-md-' + this.labelmd;
13690 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13693 if(this.labelsm > 0){
13694 labelCfg.cls += ' col-sm-' + this.labelsm;
13695 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13698 if(this.labelxs > 0){
13699 labelCfg.cls += ' col-xs-' + this.labelxs;
13700 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13704 } else if ( this.fieldLabel.length) {
13705 // Roo.log(" label");
13710 //cls : 'input-group-addon',
13711 html : this.fieldLabel
13716 if(this.indicatorpos == 'right'){
13720 //cls : 'input-group-addon',
13721 html : this.fieldLabel
13731 // Roo.log(" no label && no align");
13738 ['xs','sm','md','lg'].map(function(size){
13739 if (settings[size]) {
13740 cfg.cls += ' col-' + size + '-' + settings[size];
13748 _initEventsCalled : false,
13751 initEvents: function()
13753 if (this._initEventsCalled) { // as we call render... prevent looping...
13756 this._initEventsCalled = true;
13759 throw "can not find store for combo";
13762 this.indicator = this.indicatorEl();
13764 this.store = Roo.factory(this.store, Roo.data);
13765 this.store.parent = this;
13767 // if we are building from html. then this element is so complex, that we can not really
13768 // use the rendered HTML.
13769 // so we have to trash and replace the previous code.
13770 if (Roo.XComponent.build_from_html) {
13771 // remove this element....
13772 var e = this.el.dom, k=0;
13773 while (e ) { e = e.previousSibling; ++k;}
13778 this.rendered = false;
13780 this.render(this.parent().getChildContainer(true), k);
13783 if(Roo.isIOS && this.useNativeIOS){
13784 this.initIOSView();
13792 if(Roo.isTouch && this.mobileTouchView){
13793 this.initTouchView();
13798 this.initTickableEvents();
13802 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13804 if(this.hiddenName){
13806 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13808 this.hiddenField.dom.value =
13809 this.hiddenValue !== undefined ? this.hiddenValue :
13810 this.value !== undefined ? this.value : '';
13812 // prevent input submission
13813 this.el.dom.removeAttribute('name');
13814 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13819 // this.el.dom.setAttribute('autocomplete', 'off');
13822 var cls = 'x-combo-list';
13824 //this.list = new Roo.Layer({
13825 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13831 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13832 _this.list.setWidth(lw);
13835 this.list.on('mouseover', this.onViewOver, this);
13836 this.list.on('mousemove', this.onViewMove, this);
13837 this.list.on('scroll', this.onViewScroll, this);
13840 this.list.swallowEvent('mousewheel');
13841 this.assetHeight = 0;
13844 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13845 this.assetHeight += this.header.getHeight();
13848 this.innerList = this.list.createChild({cls:cls+'-inner'});
13849 this.innerList.on('mouseover', this.onViewOver, this);
13850 this.innerList.on('mousemove', this.onViewMove, this);
13851 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13853 if(this.allowBlank && !this.pageSize && !this.disableClear){
13854 this.footer = this.list.createChild({cls:cls+'-ft'});
13855 this.pageTb = new Roo.Toolbar(this.footer);
13859 this.footer = this.list.createChild({cls:cls+'-ft'});
13860 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13861 {pageSize: this.pageSize});
13865 if (this.pageTb && this.allowBlank && !this.disableClear) {
13867 this.pageTb.add(new Roo.Toolbar.Fill(), {
13868 cls: 'x-btn-icon x-btn-clear',
13870 handler: function()
13873 _this.clearValue();
13874 _this.onSelect(false, -1);
13879 this.assetHeight += this.footer.getHeight();
13884 this.tpl = Roo.bootstrap.version == 4 ?
13885 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13886 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13889 this.view = new Roo.View(this.list, this.tpl, {
13890 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13892 //this.view.wrapEl.setDisplayed(false);
13893 this.view.on('click', this.onViewClick, this);
13896 this.store.on('beforeload', this.onBeforeLoad, this);
13897 this.store.on('load', this.onLoad, this);
13898 this.store.on('loadexception', this.onLoadException, this);
13900 if(this.resizable){
13901 this.resizer = new Roo.Resizable(this.list, {
13902 pinned:true, handles:'se'
13904 this.resizer.on('resize', function(r, w, h){
13905 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13906 this.listWidth = w;
13907 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13908 this.restrictHeight();
13910 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13913 if(!this.editable){
13914 this.editable = true;
13915 this.setEditable(false);
13920 if (typeof(this.events.add.listeners) != 'undefined') {
13922 this.addicon = this.wrap.createChild(
13923 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13925 this.addicon.on('click', function(e) {
13926 this.fireEvent('add', this);
13929 if (typeof(this.events.edit.listeners) != 'undefined') {
13931 this.editicon = this.wrap.createChild(
13932 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13933 if (this.addicon) {
13934 this.editicon.setStyle('margin-left', '40px');
13936 this.editicon.on('click', function(e) {
13938 // we fire even if inothing is selected..
13939 this.fireEvent('edit', this, this.lastData );
13945 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13946 "up" : function(e){
13947 this.inKeyMode = true;
13951 "down" : function(e){
13952 if(!this.isExpanded()){
13953 this.onTriggerClick();
13955 this.inKeyMode = true;
13960 "enter" : function(e){
13961 // this.onViewClick();
13965 if(this.fireEvent("specialkey", this, e)){
13966 this.onViewClick(false);
13972 "esc" : function(e){
13976 "tab" : function(e){
13979 if(this.fireEvent("specialkey", this, e)){
13980 this.onViewClick(false);
13988 doRelay : function(foo, bar, hname){
13989 if(hname == 'down' || this.scope.isExpanded()){
13990 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13999 this.queryDelay = Math.max(this.queryDelay || 10,
14000 this.mode == 'local' ? 10 : 250);
14003 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14005 if(this.typeAhead){
14006 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14008 if(this.editable !== false){
14009 this.inputEl().on("keyup", this.onKeyUp, this);
14011 if(this.forceSelection){
14012 this.inputEl().on('blur', this.doForce, this);
14016 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14017 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14021 initTickableEvents: function()
14025 if(this.hiddenName){
14027 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14029 this.hiddenField.dom.value =
14030 this.hiddenValue !== undefined ? this.hiddenValue :
14031 this.value !== undefined ? this.value : '';
14033 // prevent input submission
14034 this.el.dom.removeAttribute('name');
14035 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14040 // this.list = this.el.select('ul.dropdown-menu',true).first();
14042 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14043 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14044 if(this.triggerList){
14045 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14048 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14049 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14051 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14052 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14054 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14055 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14057 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14058 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14059 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14062 this.cancelBtn.hide();
14067 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14068 _this.list.setWidth(lw);
14071 this.list.on('mouseover', this.onViewOver, this);
14072 this.list.on('mousemove', this.onViewMove, this);
14074 this.list.on('scroll', this.onViewScroll, this);
14077 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14078 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14081 this.view = new Roo.View(this.list, this.tpl, {
14086 selectedClass: this.selectedClass
14089 //this.view.wrapEl.setDisplayed(false);
14090 this.view.on('click', this.onViewClick, this);
14094 this.store.on('beforeload', this.onBeforeLoad, this);
14095 this.store.on('load', this.onLoad, this);
14096 this.store.on('loadexception', this.onLoadException, this);
14099 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14100 "up" : function(e){
14101 this.inKeyMode = true;
14105 "down" : function(e){
14106 this.inKeyMode = true;
14110 "enter" : function(e){
14111 if(this.fireEvent("specialkey", this, e)){
14112 this.onViewClick(false);
14118 "esc" : function(e){
14119 this.onTickableFooterButtonClick(e, false, false);
14122 "tab" : function(e){
14123 this.fireEvent("specialkey", this, e);
14125 this.onTickableFooterButtonClick(e, false, false);
14132 doRelay : function(e, fn, key){
14133 if(this.scope.isExpanded()){
14134 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14143 this.queryDelay = Math.max(this.queryDelay || 10,
14144 this.mode == 'local' ? 10 : 250);
14147 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14149 if(this.typeAhead){
14150 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14153 if(this.editable !== false){
14154 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14157 this.indicator = this.indicatorEl();
14159 if(this.indicator){
14160 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14161 this.indicator.hide();
14166 onDestroy : function(){
14168 this.view.setStore(null);
14169 this.view.el.removeAllListeners();
14170 this.view.el.remove();
14171 this.view.purgeListeners();
14174 this.list.dom.innerHTML = '';
14178 this.store.un('beforeload', this.onBeforeLoad, this);
14179 this.store.un('load', this.onLoad, this);
14180 this.store.un('loadexception', this.onLoadException, this);
14182 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14186 fireKey : function(e){
14187 if(e.isNavKeyPress() && !this.list.isVisible()){
14188 this.fireEvent("specialkey", this, e);
14193 onResize: function(w, h){
14194 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14196 // if(typeof w != 'number'){
14197 // // we do not handle it!?!?
14200 // var tw = this.trigger.getWidth();
14201 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14202 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14204 // this.inputEl().setWidth( this.adjustWidth('input', x));
14206 // //this.trigger.setStyle('left', x+'px');
14208 // if(this.list && this.listWidth === undefined){
14209 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14210 // this.list.setWidth(lw);
14211 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14219 * Allow or prevent the user from directly editing the field text. If false is passed,
14220 * the user will only be able to select from the items defined in the dropdown list. This method
14221 * is the runtime equivalent of setting the 'editable' config option at config time.
14222 * @param {Boolean} value True to allow the user to directly edit the field text
14224 setEditable : function(value){
14225 if(value == this.editable){
14228 this.editable = value;
14230 this.inputEl().dom.setAttribute('readOnly', true);
14231 this.inputEl().on('mousedown', this.onTriggerClick, this);
14232 this.inputEl().addClass('x-combo-noedit');
14234 this.inputEl().dom.setAttribute('readOnly', false);
14235 this.inputEl().un('mousedown', this.onTriggerClick, this);
14236 this.inputEl().removeClass('x-combo-noedit');
14242 onBeforeLoad : function(combo,opts){
14243 if(!this.hasFocus){
14247 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14249 this.restrictHeight();
14250 this.selectedIndex = -1;
14254 onLoad : function(){
14256 this.hasQuery = false;
14258 if(!this.hasFocus){
14262 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14263 this.loading.hide();
14266 if(this.store.getCount() > 0){
14269 this.restrictHeight();
14270 if(this.lastQuery == this.allQuery){
14271 if(this.editable && !this.tickable){
14272 this.inputEl().dom.select();
14276 !this.selectByValue(this.value, true) &&
14279 !this.store.lastOptions ||
14280 typeof(this.store.lastOptions.add) == 'undefined' ||
14281 this.store.lastOptions.add != true
14284 this.select(0, true);
14287 if(this.autoFocus){
14290 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14291 this.taTask.delay(this.typeAheadDelay);
14295 this.onEmptyResults();
14301 onLoadException : function()
14303 this.hasQuery = false;
14305 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14306 this.loading.hide();
14309 if(this.tickable && this.editable){
14314 // only causes errors at present
14315 //Roo.log(this.store.reader.jsonData);
14316 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14318 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14324 onTypeAhead : function(){
14325 if(this.store.getCount() > 0){
14326 var r = this.store.getAt(0);
14327 var newValue = r.data[this.displayField];
14328 var len = newValue.length;
14329 var selStart = this.getRawValue().length;
14331 if(selStart != len){
14332 this.setRawValue(newValue);
14333 this.selectText(selStart, newValue.length);
14339 onSelect : function(record, index){
14341 if(this.fireEvent('beforeselect', this, record, index) !== false){
14343 this.setFromData(index > -1 ? record.data : false);
14346 this.fireEvent('select', this, record, index);
14351 * Returns the currently selected field value or empty string if no value is set.
14352 * @return {String} value The selected value
14354 getValue : function()
14356 if(Roo.isIOS && this.useNativeIOS){
14357 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14361 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14364 if(this.valueField){
14365 return typeof this.value != 'undefined' ? this.value : '';
14367 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14371 getRawValue : function()
14373 if(Roo.isIOS && this.useNativeIOS){
14374 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14377 var v = this.inputEl().getValue();
14383 * Clears any text/value currently set in the field
14385 clearValue : function(){
14387 if(this.hiddenField){
14388 this.hiddenField.dom.value = '';
14391 this.setRawValue('');
14392 this.lastSelectionText = '';
14393 this.lastData = false;
14395 var close = this.closeTriggerEl();
14406 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14407 * will be displayed in the field. If the value does not match the data value of an existing item,
14408 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14409 * Otherwise the field will be blank (although the value will still be set).
14410 * @param {String} value The value to match
14412 setValue : function(v)
14414 if(Roo.isIOS && this.useNativeIOS){
14415 this.setIOSValue(v);
14425 if(this.valueField){
14426 var r = this.findRecord(this.valueField, v);
14428 text = r.data[this.displayField];
14429 }else if(this.valueNotFoundText !== undefined){
14430 text = this.valueNotFoundText;
14433 this.lastSelectionText = text;
14434 if(this.hiddenField){
14435 this.hiddenField.dom.value = v;
14437 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14440 var close = this.closeTriggerEl();
14443 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14449 * @property {Object} the last set data for the element
14454 * Sets the value of the field based on a object which is related to the record format for the store.
14455 * @param {Object} value the value to set as. or false on reset?
14457 setFromData : function(o){
14464 var dv = ''; // display value
14465 var vv = ''; // value value..
14467 if (this.displayField) {
14468 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14470 // this is an error condition!!!
14471 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14474 if(this.valueField){
14475 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14478 var close = this.closeTriggerEl();
14481 if(dv.length || vv * 1 > 0){
14483 this.blockFocus=true;
14489 if(this.hiddenField){
14490 this.hiddenField.dom.value = vv;
14492 this.lastSelectionText = dv;
14493 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14497 // no hidden field.. - we store the value in 'value', but still display
14498 // display field!!!!
14499 this.lastSelectionText = dv;
14500 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14507 reset : function(){
14508 // overridden so that last data is reset..
14515 this.setValue(this.originalValue);
14516 //this.clearInvalid();
14517 this.lastData = false;
14519 this.view.clearSelections();
14525 findRecord : function(prop, value){
14527 if(this.store.getCount() > 0){
14528 this.store.each(function(r){
14529 if(r.data[prop] == value){
14539 getName: function()
14541 // returns hidden if it's set..
14542 if (!this.rendered) {return ''};
14543 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14547 onViewMove : function(e, t){
14548 this.inKeyMode = false;
14552 onViewOver : function(e, t){
14553 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14556 var item = this.view.findItemFromChild(t);
14559 var index = this.view.indexOf(item);
14560 this.select(index, false);
14565 onViewClick : function(view, doFocus, el, e)
14567 var index = this.view.getSelectedIndexes()[0];
14569 var r = this.store.getAt(index);
14573 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14580 Roo.each(this.tickItems, function(v,k){
14582 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14584 _this.tickItems.splice(k, 1);
14586 if(typeof(e) == 'undefined' && view == false){
14587 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14599 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14600 this.tickItems.push(r.data);
14603 if(typeof(e) == 'undefined' && view == false){
14604 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14611 this.onSelect(r, index);
14613 if(doFocus !== false && !this.blockFocus){
14614 this.inputEl().focus();
14619 restrictHeight : function(){
14620 //this.innerList.dom.style.height = '';
14621 //var inner = this.innerList.dom;
14622 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14623 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14624 //this.list.beginUpdate();
14625 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14626 this.list.alignTo(this.inputEl(), this.listAlign);
14627 this.list.alignTo(this.inputEl(), this.listAlign);
14628 //this.list.endUpdate();
14632 onEmptyResults : function(){
14634 if(this.tickable && this.editable){
14635 this.hasFocus = false;
14636 this.restrictHeight();
14644 * Returns true if the dropdown list is expanded, else false.
14646 isExpanded : function(){
14647 return this.list.isVisible();
14651 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14652 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14653 * @param {String} value The data value of the item to select
14654 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14655 * selected item if it is not currently in view (defaults to true)
14656 * @return {Boolean} True if the value matched an item in the list, else false
14658 selectByValue : function(v, scrollIntoView){
14659 if(v !== undefined && v !== null){
14660 var r = this.findRecord(this.valueField || this.displayField, v);
14662 this.select(this.store.indexOf(r), scrollIntoView);
14670 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14671 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14672 * @param {Number} index The zero-based index of the list item to select
14673 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14674 * selected item if it is not currently in view (defaults to true)
14676 select : function(index, scrollIntoView){
14677 this.selectedIndex = index;
14678 this.view.select(index);
14679 if(scrollIntoView !== false){
14680 var el = this.view.getNode(index);
14682 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14685 this.list.scrollChildIntoView(el, false);
14691 selectNext : function(){
14692 var ct = this.store.getCount();
14694 if(this.selectedIndex == -1){
14696 }else if(this.selectedIndex < ct-1){
14697 this.select(this.selectedIndex+1);
14703 selectPrev : function(){
14704 var ct = this.store.getCount();
14706 if(this.selectedIndex == -1){
14708 }else if(this.selectedIndex != 0){
14709 this.select(this.selectedIndex-1);
14715 onKeyUp : function(e){
14716 if(this.editable !== false && !e.isSpecialKey()){
14717 this.lastKey = e.getKey();
14718 this.dqTask.delay(this.queryDelay);
14723 validateBlur : function(){
14724 return !this.list || !this.list.isVisible();
14728 initQuery : function(){
14730 var v = this.getRawValue();
14732 if(this.tickable && this.editable){
14733 v = this.tickableInputEl().getValue();
14740 doForce : function(){
14741 if(this.inputEl().dom.value.length > 0){
14742 this.inputEl().dom.value =
14743 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14749 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14750 * query allowing the query action to be canceled if needed.
14751 * @param {String} query The SQL query to execute
14752 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14753 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14754 * saved in the current store (defaults to false)
14756 doQuery : function(q, forceAll){
14758 if(q === undefined || q === null){
14763 forceAll: forceAll,
14767 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14772 forceAll = qe.forceAll;
14773 if(forceAll === true || (q.length >= this.minChars)){
14775 this.hasQuery = true;
14777 if(this.lastQuery != q || this.alwaysQuery){
14778 this.lastQuery = q;
14779 if(this.mode == 'local'){
14780 this.selectedIndex = -1;
14782 this.store.clearFilter();
14785 if(this.specialFilter){
14786 this.fireEvent('specialfilter', this);
14791 this.store.filter(this.displayField, q);
14794 this.store.fireEvent("datachanged", this.store);
14801 this.store.baseParams[this.queryParam] = q;
14803 var options = {params : this.getParams(q)};
14806 options.add = true;
14807 options.params.start = this.page * this.pageSize;
14810 this.store.load(options);
14813 * this code will make the page width larger, at the beginning, the list not align correctly,
14814 * we should expand the list on onLoad
14815 * so command out it
14820 this.selectedIndex = -1;
14825 this.loadNext = false;
14829 getParams : function(q){
14831 //p[this.queryParam] = q;
14835 p.limit = this.pageSize;
14841 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14843 collapse : function(){
14844 if(!this.isExpanded()){
14850 this.hasFocus = false;
14854 this.cancelBtn.hide();
14855 this.trigger.show();
14858 this.tickableInputEl().dom.value = '';
14859 this.tickableInputEl().blur();
14864 Roo.get(document).un('mousedown', this.collapseIf, this);
14865 Roo.get(document).un('mousewheel', this.collapseIf, this);
14866 if (!this.editable) {
14867 Roo.get(document).un('keydown', this.listKeyPress, this);
14869 this.fireEvent('collapse', this);
14875 collapseIf : function(e){
14876 var in_combo = e.within(this.el);
14877 var in_list = e.within(this.list);
14878 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14880 if (in_combo || in_list || is_list) {
14881 //e.stopPropagation();
14886 this.onTickableFooterButtonClick(e, false, false);
14894 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14896 expand : function(){
14898 if(this.isExpanded() || !this.hasFocus){
14902 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14903 this.list.setWidth(lw);
14909 this.restrictHeight();
14913 this.tickItems = Roo.apply([], this.item);
14916 this.cancelBtn.show();
14917 this.trigger.hide();
14920 this.tickableInputEl().focus();
14925 Roo.get(document).on('mousedown', this.collapseIf, this);
14926 Roo.get(document).on('mousewheel', this.collapseIf, this);
14927 if (!this.editable) {
14928 Roo.get(document).on('keydown', this.listKeyPress, this);
14931 this.fireEvent('expand', this);
14935 // Implements the default empty TriggerField.onTriggerClick function
14936 onTriggerClick : function(e)
14938 Roo.log('trigger click');
14940 if(this.disabled || !this.triggerList){
14945 this.loadNext = false;
14947 if(this.isExpanded()){
14949 if (!this.blockFocus) {
14950 this.inputEl().focus();
14954 this.hasFocus = true;
14955 if(this.triggerAction == 'all') {
14956 this.doQuery(this.allQuery, true);
14958 this.doQuery(this.getRawValue());
14960 if (!this.blockFocus) {
14961 this.inputEl().focus();
14966 onTickableTriggerClick : function(e)
14973 this.loadNext = false;
14974 this.hasFocus = true;
14976 if(this.triggerAction == 'all') {
14977 this.doQuery(this.allQuery, true);
14979 this.doQuery(this.getRawValue());
14983 onSearchFieldClick : function(e)
14985 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14986 this.onTickableFooterButtonClick(e, false, false);
14990 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14995 this.loadNext = false;
14996 this.hasFocus = true;
14998 if(this.triggerAction == 'all') {
14999 this.doQuery(this.allQuery, true);
15001 this.doQuery(this.getRawValue());
15005 listKeyPress : function(e)
15007 //Roo.log('listkeypress');
15008 // scroll to first matching element based on key pres..
15009 if (e.isSpecialKey()) {
15012 var k = String.fromCharCode(e.getKey()).toUpperCase();
15015 var csel = this.view.getSelectedNodes();
15016 var cselitem = false;
15018 var ix = this.view.indexOf(csel[0]);
15019 cselitem = this.store.getAt(ix);
15020 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15026 this.store.each(function(v) {
15028 // start at existing selection.
15029 if (cselitem.id == v.id) {
15035 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15036 match = this.store.indexOf(v);
15042 if (match === false) {
15043 return true; // no more action?
15046 this.view.select(match);
15047 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15048 sn.scrollIntoView(sn.dom.parentNode, false);
15051 onViewScroll : function(e, t){
15053 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){
15057 this.hasQuery = true;
15059 this.loading = this.list.select('.loading', true).first();
15061 if(this.loading === null){
15062 this.list.createChild({
15064 cls: 'loading roo-select2-more-results roo-select2-active',
15065 html: 'Loading more results...'
15068 this.loading = this.list.select('.loading', true).first();
15070 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15072 this.loading.hide();
15075 this.loading.show();
15080 this.loadNext = true;
15082 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15087 addItem : function(o)
15089 var dv = ''; // display value
15091 if (this.displayField) {
15092 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15094 // this is an error condition!!!
15095 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15102 var choice = this.choices.createChild({
15104 cls: 'roo-select2-search-choice',
15113 cls: 'roo-select2-search-choice-close fa fa-times',
15118 }, this.searchField);
15120 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15122 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15130 this.inputEl().dom.value = '';
15135 onRemoveItem : function(e, _self, o)
15137 e.preventDefault();
15139 this.lastItem = Roo.apply([], this.item);
15141 var index = this.item.indexOf(o.data) * 1;
15144 Roo.log('not this item?!');
15148 this.item.splice(index, 1);
15153 this.fireEvent('remove', this, e);
15159 syncValue : function()
15161 if(!this.item.length){
15168 Roo.each(this.item, function(i){
15169 if(_this.valueField){
15170 value.push(i[_this.valueField]);
15177 this.value = value.join(',');
15179 if(this.hiddenField){
15180 this.hiddenField.dom.value = this.value;
15183 this.store.fireEvent("datachanged", this.store);
15188 clearItem : function()
15190 if(!this.multiple){
15196 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15204 if(this.tickable && !Roo.isTouch){
15205 this.view.refresh();
15209 inputEl: function ()
15211 if(Roo.isIOS && this.useNativeIOS){
15212 return this.el.select('select.roo-ios-select', true).first();
15215 if(Roo.isTouch && this.mobileTouchView){
15216 return this.el.select('input.form-control',true).first();
15220 return this.searchField;
15223 return this.el.select('input.form-control',true).first();
15226 onTickableFooterButtonClick : function(e, btn, el)
15228 e.preventDefault();
15230 this.lastItem = Roo.apply([], this.item);
15232 if(btn && btn.name == 'cancel'){
15233 this.tickItems = Roo.apply([], this.item);
15242 Roo.each(this.tickItems, function(o){
15250 validate : function()
15252 if(this.getVisibilityEl().hasClass('hidden')){
15256 var v = this.getRawValue();
15259 v = this.getValue();
15262 if(this.disabled || this.allowBlank || v.length){
15267 this.markInvalid();
15271 tickableInputEl : function()
15273 if(!this.tickable || !this.editable){
15274 return this.inputEl();
15277 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15281 getAutoCreateTouchView : function()
15286 cls: 'form-group' //input-group
15292 type : this.inputType,
15293 cls : 'form-control x-combo-noedit',
15294 autocomplete: 'new-password',
15295 placeholder : this.placeholder || '',
15300 input.name = this.name;
15304 input.cls += ' input-' + this.size;
15307 if (this.disabled) {
15308 input.disabled = true;
15319 inputblock.cls += ' input-group';
15321 inputblock.cn.unshift({
15323 cls : 'input-group-addon input-group-prepend input-group-text',
15328 if(this.removable && !this.multiple){
15329 inputblock.cls += ' roo-removable';
15331 inputblock.cn.push({
15334 cls : 'roo-combo-removable-btn close'
15338 if(this.hasFeedback && !this.allowBlank){
15340 inputblock.cls += ' has-feedback';
15342 inputblock.cn.push({
15344 cls: 'glyphicon form-control-feedback'
15351 inputblock.cls += (this.before) ? '' : ' input-group';
15353 inputblock.cn.push({
15355 cls : 'input-group-addon input-group-append input-group-text',
15361 var ibwrap = inputblock;
15366 cls: 'roo-select2-choices',
15370 cls: 'roo-select2-search-field',
15383 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15388 cls: 'form-hidden-field'
15394 if(!this.multiple && this.showToggleBtn){
15400 if (this.caret != false) {
15403 cls: 'fa fa-' + this.caret
15410 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15412 Roo.bootstrap.version == 3 ? caret : '',
15415 cls: 'combobox-clear',
15429 combobox.cls += ' roo-select2-container-multi';
15432 var align = this.labelAlign || this.parentLabelAlign();
15434 if (align ==='left' && this.fieldLabel.length) {
15439 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15440 tooltip : 'This field is required'
15444 cls : 'control-label col-form-label',
15445 html : this.fieldLabel
15456 var labelCfg = cfg.cn[1];
15457 var contentCfg = cfg.cn[2];
15460 if(this.indicatorpos == 'right'){
15465 cls : 'control-label col-form-label',
15469 html : this.fieldLabel
15473 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15474 tooltip : 'This field is required'
15487 labelCfg = cfg.cn[0];
15488 contentCfg = cfg.cn[1];
15493 if(this.labelWidth > 12){
15494 labelCfg.style = "width: " + this.labelWidth + 'px';
15497 if(this.labelWidth < 13 && this.labelmd == 0){
15498 this.labelmd = this.labelWidth;
15501 if(this.labellg > 0){
15502 labelCfg.cls += ' col-lg-' + this.labellg;
15503 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15506 if(this.labelmd > 0){
15507 labelCfg.cls += ' col-md-' + this.labelmd;
15508 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15511 if(this.labelsm > 0){
15512 labelCfg.cls += ' col-sm-' + this.labelsm;
15513 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15516 if(this.labelxs > 0){
15517 labelCfg.cls += ' col-xs-' + this.labelxs;
15518 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15522 } else if ( this.fieldLabel.length) {
15526 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15527 tooltip : 'This field is required'
15531 cls : 'control-label',
15532 html : this.fieldLabel
15543 if(this.indicatorpos == 'right'){
15547 cls : 'control-label',
15548 html : this.fieldLabel,
15552 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15553 tooltip : 'This field is required'
15570 var settings = this;
15572 ['xs','sm','md','lg'].map(function(size){
15573 if (settings[size]) {
15574 cfg.cls += ' col-' + size + '-' + settings[size];
15581 initTouchView : function()
15583 this.renderTouchView();
15585 this.touchViewEl.on('scroll', function(){
15586 this.el.dom.scrollTop = 0;
15589 this.originalValue = this.getValue();
15591 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15593 this.inputEl().on("click", this.showTouchView, this);
15594 if (this.triggerEl) {
15595 this.triggerEl.on("click", this.showTouchView, this);
15599 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15600 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15602 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15604 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15605 this.store.on('load', this.onTouchViewLoad, this);
15606 this.store.on('loadexception', this.onTouchViewLoadException, this);
15608 if(this.hiddenName){
15610 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15612 this.hiddenField.dom.value =
15613 this.hiddenValue !== undefined ? this.hiddenValue :
15614 this.value !== undefined ? this.value : '';
15616 this.el.dom.removeAttribute('name');
15617 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15621 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15622 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15625 if(this.removable && !this.multiple){
15626 var close = this.closeTriggerEl();
15628 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15629 close.on('click', this.removeBtnClick, this, close);
15633 * fix the bug in Safari iOS8
15635 this.inputEl().on("focus", function(e){
15636 document.activeElement.blur();
15639 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15646 renderTouchView : function()
15648 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15649 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15651 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15652 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15654 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15655 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15656 this.touchViewBodyEl.setStyle('overflow', 'auto');
15658 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15659 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15661 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15662 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15666 showTouchView : function()
15672 this.touchViewHeaderEl.hide();
15674 if(this.modalTitle.length){
15675 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15676 this.touchViewHeaderEl.show();
15679 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15680 this.touchViewEl.show();
15682 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15684 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15685 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15687 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15689 if(this.modalTitle.length){
15690 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15693 this.touchViewBodyEl.setHeight(bodyHeight);
15697 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15699 this.touchViewEl.addClass('in');
15702 if(this._touchViewMask){
15703 Roo.get(document.body).addClass("x-body-masked");
15704 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15705 this._touchViewMask.setStyle('z-index', 10000);
15706 this._touchViewMask.addClass('show');
15709 this.doTouchViewQuery();
15713 hideTouchView : function()
15715 this.touchViewEl.removeClass('in');
15719 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15721 this.touchViewEl.setStyle('display', 'none');
15724 if(this._touchViewMask){
15725 this._touchViewMask.removeClass('show');
15726 Roo.get(document.body).removeClass("x-body-masked");
15730 setTouchViewValue : function()
15737 Roo.each(this.tickItems, function(o){
15742 this.hideTouchView();
15745 doTouchViewQuery : function()
15754 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15758 if(!this.alwaysQuery || this.mode == 'local'){
15759 this.onTouchViewLoad();
15766 onTouchViewBeforeLoad : function(combo,opts)
15772 onTouchViewLoad : function()
15774 if(this.store.getCount() < 1){
15775 this.onTouchViewEmptyResults();
15779 this.clearTouchView();
15781 var rawValue = this.getRawValue();
15783 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15785 this.tickItems = [];
15787 this.store.data.each(function(d, rowIndex){
15788 var row = this.touchViewListGroup.createChild(template);
15790 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15791 row.addClass(d.data.cls);
15794 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15797 html : d.data[this.displayField]
15800 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15801 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15804 row.removeClass('selected');
15805 if(!this.multiple && this.valueField &&
15806 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15809 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15810 row.addClass('selected');
15813 if(this.multiple && this.valueField &&
15814 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15818 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15819 this.tickItems.push(d.data);
15822 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15826 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15828 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15830 if(this.modalTitle.length){
15831 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15834 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15836 if(this.mobile_restrict_height && listHeight < bodyHeight){
15837 this.touchViewBodyEl.setHeight(listHeight);
15842 if(firstChecked && listHeight > bodyHeight){
15843 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15848 onTouchViewLoadException : function()
15850 this.hideTouchView();
15853 onTouchViewEmptyResults : function()
15855 this.clearTouchView();
15857 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15859 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15863 clearTouchView : function()
15865 this.touchViewListGroup.dom.innerHTML = '';
15868 onTouchViewClick : function(e, el, o)
15870 e.preventDefault();
15873 var rowIndex = o.rowIndex;
15875 var r = this.store.getAt(rowIndex);
15877 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15879 if(!this.multiple){
15880 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15881 c.dom.removeAttribute('checked');
15884 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15886 this.setFromData(r.data);
15888 var close = this.closeTriggerEl();
15894 this.hideTouchView();
15896 this.fireEvent('select', this, r, rowIndex);
15901 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15902 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15903 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15907 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15908 this.addItem(r.data);
15909 this.tickItems.push(r.data);
15913 getAutoCreateNativeIOS : function()
15916 cls: 'form-group' //input-group,
15921 cls : 'roo-ios-select'
15925 combobox.name = this.name;
15928 if (this.disabled) {
15929 combobox.disabled = true;
15932 var settings = this;
15934 ['xs','sm','md','lg'].map(function(size){
15935 if (settings[size]) {
15936 cfg.cls += ' col-' + size + '-' + settings[size];
15946 initIOSView : function()
15948 this.store.on('load', this.onIOSViewLoad, this);
15953 onIOSViewLoad : function()
15955 if(this.store.getCount() < 1){
15959 this.clearIOSView();
15961 if(this.allowBlank) {
15963 var default_text = '-- SELECT --';
15965 if(this.placeholder.length){
15966 default_text = this.placeholder;
15969 if(this.emptyTitle.length){
15970 default_text += ' - ' + this.emptyTitle + ' -';
15973 var opt = this.inputEl().createChild({
15976 html : default_text
15980 o[this.valueField] = 0;
15981 o[this.displayField] = default_text;
15983 this.ios_options.push({
15990 this.store.data.each(function(d, rowIndex){
15994 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15995 html = d.data[this.displayField];
16000 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16001 value = d.data[this.valueField];
16010 if(this.value == d.data[this.valueField]){
16011 option['selected'] = true;
16014 var opt = this.inputEl().createChild(option);
16016 this.ios_options.push({
16023 this.inputEl().on('change', function(){
16024 this.fireEvent('select', this);
16029 clearIOSView: function()
16031 this.inputEl().dom.innerHTML = '';
16033 this.ios_options = [];
16036 setIOSValue: function(v)
16040 if(!this.ios_options){
16044 Roo.each(this.ios_options, function(opts){
16046 opts.el.dom.removeAttribute('selected');
16048 if(opts.data[this.valueField] != v){
16052 opts.el.dom.setAttribute('selected', true);
16058 * @cfg {Boolean} grow
16062 * @cfg {Number} growMin
16066 * @cfg {Number} growMax
16075 Roo.apply(Roo.bootstrap.ComboBox, {
16079 cls: 'modal-header',
16101 cls: 'list-group-item',
16105 cls: 'roo-combobox-list-group-item-value'
16109 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16123 listItemCheckbox : {
16125 cls: 'list-group-item',
16129 cls: 'roo-combobox-list-group-item-value'
16133 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16149 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16154 cls: 'modal-footer',
16162 cls: 'col-xs-6 text-left',
16165 cls: 'btn btn-danger roo-touch-view-cancel',
16171 cls: 'col-xs-6 text-right',
16174 cls: 'btn btn-success roo-touch-view-ok',
16185 Roo.apply(Roo.bootstrap.ComboBox, {
16187 touchViewTemplate : {
16189 cls: 'modal fade roo-combobox-touch-view',
16193 cls: 'modal-dialog',
16194 style : 'position:fixed', // we have to fix position....
16198 cls: 'modal-content',
16200 Roo.bootstrap.ComboBox.header,
16201 Roo.bootstrap.ComboBox.body,
16202 Roo.bootstrap.ComboBox.footer
16211 * Ext JS Library 1.1.1
16212 * Copyright(c) 2006-2007, Ext JS, LLC.
16214 * Originally Released Under LGPL - original licence link has changed is not relivant.
16217 * <script type="text/javascript">
16222 * @extends Roo.util.Observable
16223 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16224 * This class also supports single and multi selection modes. <br>
16225 * Create a data model bound view:
16227 var store = new Roo.data.Store(...);
16229 var view = new Roo.View({
16231 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16233 singleSelect: true,
16234 selectedClass: "ydataview-selected",
16238 // listen for node click?
16239 view.on("click", function(vw, index, node, e){
16240 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16244 dataModel.load("foobar.xml");
16246 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16248 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16249 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16251 * Note: old style constructor is still suported (container, template, config)
16254 * Create a new View
16255 * @param {Object} config The config object
16258 Roo.View = function(config, depreciated_tpl, depreciated_config){
16260 this.parent = false;
16262 if (typeof(depreciated_tpl) == 'undefined') {
16263 // new way.. - universal constructor.
16264 Roo.apply(this, config);
16265 this.el = Roo.get(this.el);
16268 this.el = Roo.get(config);
16269 this.tpl = depreciated_tpl;
16270 Roo.apply(this, depreciated_config);
16272 this.wrapEl = this.el.wrap().wrap();
16273 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16276 if(typeof(this.tpl) == "string"){
16277 this.tpl = new Roo.Template(this.tpl);
16279 // support xtype ctors..
16280 this.tpl = new Roo.factory(this.tpl, Roo);
16284 this.tpl.compile();
16289 * @event beforeclick
16290 * Fires before a click is processed. Returns false to cancel the default action.
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
16296 "beforeclick" : true,
16299 * Fires when a template node is 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
16308 * Fires when a template node is double 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
16316 * @event contextmenu
16317 * Fires when a template node is right clicked.
16318 * @param {Roo.View} this
16319 * @param {Number} index The index of the target node
16320 * @param {HTMLElement} node The target node
16321 * @param {Roo.EventObject} e The raw event object
16323 "contextmenu" : true,
16325 * @event selectionchange
16326 * Fires when the selected nodes change.
16327 * @param {Roo.View} this
16328 * @param {Array} selections Array of the selected nodes
16330 "selectionchange" : true,
16333 * @event beforeselect
16334 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16335 * @param {Roo.View} this
16336 * @param {HTMLElement} node The node to be selected
16337 * @param {Array} selections Array of currently selected nodes
16339 "beforeselect" : true,
16341 * @event preparedata
16342 * Fires on every row to render, to allow you to change the data.
16343 * @param {Roo.View} this
16344 * @param {Object} data to be rendered (change this)
16346 "preparedata" : true
16354 "click": this.onClick,
16355 "dblclick": this.onDblClick,
16356 "contextmenu": this.onContextMenu,
16360 this.selections = [];
16362 this.cmp = new Roo.CompositeElementLite([]);
16364 this.store = Roo.factory(this.store, Roo.data);
16365 this.setStore(this.store, true);
16368 if ( this.footer && this.footer.xtype) {
16370 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16372 this.footer.dataSource = this.store;
16373 this.footer.container = fctr;
16374 this.footer = Roo.factory(this.footer, Roo);
16375 fctr.insertFirst(this.el);
16377 // this is a bit insane - as the paging toolbar seems to detach the el..
16378 // dom.parentNode.parentNode.parentNode
16379 // they get detached?
16383 Roo.View.superclass.constructor.call(this);
16388 Roo.extend(Roo.View, Roo.util.Observable, {
16391 * @cfg {Roo.data.Store} store Data store to load data from.
16396 * @cfg {String|Roo.Element} el The container element.
16401 * @cfg {String|Roo.Template} tpl The template used by this View
16405 * @cfg {String} dataName the named area of the template to use as the data area
16406 * Works with domtemplates roo-name="name"
16410 * @cfg {String} selectedClass The css class to add to selected nodes
16412 selectedClass : "x-view-selected",
16414 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16419 * @cfg {String} text to display on mask (default Loading)
16423 * @cfg {Boolean} multiSelect Allow multiple selection
16425 multiSelect : false,
16427 * @cfg {Boolean} singleSelect Allow single selection
16429 singleSelect: false,
16432 * @cfg {Boolean} toggleSelect - selecting
16434 toggleSelect : false,
16437 * @cfg {Boolean} tickable - selecting
16442 * Returns the element this view is bound to.
16443 * @return {Roo.Element}
16445 getEl : function(){
16446 return this.wrapEl;
16452 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16454 refresh : function(){
16455 //Roo.log('refresh');
16458 // if we are using something like 'domtemplate', then
16459 // the what gets used is:
16460 // t.applySubtemplate(NAME, data, wrapping data..)
16461 // the outer template then get' applied with
16462 // the store 'extra data'
16463 // and the body get's added to the
16464 // roo-name="data" node?
16465 // <span class='roo-tpl-{name}'></span> ?????
16469 this.clearSelections();
16470 this.el.update("");
16472 var records = this.store.getRange();
16473 if(records.length < 1) {
16475 // is this valid?? = should it render a template??
16477 this.el.update(this.emptyText);
16481 if (this.dataName) {
16482 this.el.update(t.apply(this.store.meta)); //????
16483 el = this.el.child('.roo-tpl-' + this.dataName);
16486 for(var i = 0, len = records.length; i < len; i++){
16487 var data = this.prepareData(records[i].data, i, records[i]);
16488 this.fireEvent("preparedata", this, data, i, records[i]);
16490 var d = Roo.apply({}, data);
16493 Roo.apply(d, {'roo-id' : Roo.id()});
16497 Roo.each(this.parent.item, function(item){
16498 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16501 Roo.apply(d, {'roo-data-checked' : 'checked'});
16505 html[html.length] = Roo.util.Format.trim(
16507 t.applySubtemplate(this.dataName, d, this.store.meta) :
16514 el.update(html.join(""));
16515 this.nodes = el.dom.childNodes;
16516 this.updateIndexes(0);
16521 * Function to override to reformat the data that is sent to
16522 * the template for each node.
16523 * DEPRICATED - use the preparedata event handler.
16524 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16525 * a JSON object for an UpdateManager bound view).
16527 prepareData : function(data, index, record)
16529 this.fireEvent("preparedata", this, data, index, record);
16533 onUpdate : function(ds, record){
16534 // Roo.log('on update');
16535 this.clearSelections();
16536 var index = this.store.indexOf(record);
16537 var n = this.nodes[index];
16538 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16539 n.parentNode.removeChild(n);
16540 this.updateIndexes(index, index);
16546 onAdd : function(ds, records, index)
16548 //Roo.log(['on Add', ds, records, index] );
16549 this.clearSelections();
16550 if(this.nodes.length == 0){
16554 var n = this.nodes[index];
16555 for(var i = 0, len = records.length; i < len; i++){
16556 var d = this.prepareData(records[i].data, i, records[i]);
16558 this.tpl.insertBefore(n, d);
16561 this.tpl.append(this.el, d);
16564 this.updateIndexes(index);
16567 onRemove : function(ds, record, index){
16568 // Roo.log('onRemove');
16569 this.clearSelections();
16570 var el = this.dataName ?
16571 this.el.child('.roo-tpl-' + this.dataName) :
16574 el.dom.removeChild(this.nodes[index]);
16575 this.updateIndexes(index);
16579 * Refresh an individual node.
16580 * @param {Number} index
16582 refreshNode : function(index){
16583 this.onUpdate(this.store, this.store.getAt(index));
16586 updateIndexes : function(startIndex, endIndex){
16587 var ns = this.nodes;
16588 startIndex = startIndex || 0;
16589 endIndex = endIndex || ns.length - 1;
16590 for(var i = startIndex; i <= endIndex; i++){
16591 ns[i].nodeIndex = i;
16596 * Changes the data store this view uses and refresh the view.
16597 * @param {Store} store
16599 setStore : function(store, initial){
16600 if(!initial && this.store){
16601 this.store.un("datachanged", this.refresh);
16602 this.store.un("add", this.onAdd);
16603 this.store.un("remove", this.onRemove);
16604 this.store.un("update", this.onUpdate);
16605 this.store.un("clear", this.refresh);
16606 this.store.un("beforeload", this.onBeforeLoad);
16607 this.store.un("load", this.onLoad);
16608 this.store.un("loadexception", this.onLoad);
16612 store.on("datachanged", this.refresh, this);
16613 store.on("add", this.onAdd, this);
16614 store.on("remove", this.onRemove, this);
16615 store.on("update", this.onUpdate, this);
16616 store.on("clear", this.refresh, this);
16617 store.on("beforeload", this.onBeforeLoad, this);
16618 store.on("load", this.onLoad, this);
16619 store.on("loadexception", this.onLoad, this);
16627 * onbeforeLoad - masks the loading area.
16630 onBeforeLoad : function(store,opts)
16632 //Roo.log('onBeforeLoad');
16634 this.el.update("");
16636 this.el.mask(this.mask ? this.mask : "Loading" );
16638 onLoad : function ()
16645 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16646 * @param {HTMLElement} node
16647 * @return {HTMLElement} The template node
16649 findItemFromChild : function(node){
16650 var el = this.dataName ?
16651 this.el.child('.roo-tpl-' + this.dataName,true) :
16654 if(!node || node.parentNode == el){
16657 var p = node.parentNode;
16658 while(p && p != el){
16659 if(p.parentNode == el){
16668 onClick : function(e){
16669 var item = this.findItemFromChild(e.getTarget());
16671 var index = this.indexOf(item);
16672 if(this.onItemClick(item, index, e) !== false){
16673 this.fireEvent("click", this, index, item, e);
16676 this.clearSelections();
16681 onContextMenu : function(e){
16682 var item = this.findItemFromChild(e.getTarget());
16684 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16689 onDblClick : function(e){
16690 var item = this.findItemFromChild(e.getTarget());
16692 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16696 onItemClick : function(item, index, e)
16698 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16701 if (this.toggleSelect) {
16702 var m = this.isSelected(item) ? 'unselect' : 'select';
16705 _t[m](item, true, false);
16708 if(this.multiSelect || this.singleSelect){
16709 if(this.multiSelect && e.shiftKey && this.lastSelection){
16710 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16712 this.select(item, this.multiSelect && e.ctrlKey);
16713 this.lastSelection = item;
16716 if(!this.tickable){
16717 e.preventDefault();
16725 * Get the number of selected nodes.
16728 getSelectionCount : function(){
16729 return this.selections.length;
16733 * Get the currently selected nodes.
16734 * @return {Array} An array of HTMLElements
16736 getSelectedNodes : function(){
16737 return this.selections;
16741 * Get the indexes of the selected nodes.
16744 getSelectedIndexes : function(){
16745 var indexes = [], s = this.selections;
16746 for(var i = 0, len = s.length; i < len; i++){
16747 indexes.push(s[i].nodeIndex);
16753 * Clear all selections
16754 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16756 clearSelections : function(suppressEvent){
16757 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16758 this.cmp.elements = this.selections;
16759 this.cmp.removeClass(this.selectedClass);
16760 this.selections = [];
16761 if(!suppressEvent){
16762 this.fireEvent("selectionchange", this, this.selections);
16768 * Returns true if the passed node is selected
16769 * @param {HTMLElement/Number} node The node or node index
16770 * @return {Boolean}
16772 isSelected : function(node){
16773 var s = this.selections;
16777 node = this.getNode(node);
16778 return s.indexOf(node) !== -1;
16783 * @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
16784 * @param {Boolean} keepExisting (optional) true to keep existing selections
16785 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16787 select : function(nodeInfo, keepExisting, suppressEvent){
16788 if(nodeInfo instanceof Array){
16790 this.clearSelections(true);
16792 for(var i = 0, len = nodeInfo.length; i < len; i++){
16793 this.select(nodeInfo[i], true, true);
16797 var node = this.getNode(nodeInfo);
16798 if(!node || this.isSelected(node)){
16799 return; // already selected.
16802 this.clearSelections(true);
16805 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16806 Roo.fly(node).addClass(this.selectedClass);
16807 this.selections.push(node);
16808 if(!suppressEvent){
16809 this.fireEvent("selectionchange", this, this.selections);
16817 * @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
16818 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16819 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16821 unselect : function(nodeInfo, keepExisting, suppressEvent)
16823 if(nodeInfo instanceof Array){
16824 Roo.each(this.selections, function(s) {
16825 this.unselect(s, nodeInfo);
16829 var node = this.getNode(nodeInfo);
16830 if(!node || !this.isSelected(node)){
16831 //Roo.log("not selected");
16832 return; // not selected.
16836 Roo.each(this.selections, function(s) {
16838 Roo.fly(node).removeClass(this.selectedClass);
16845 this.selections= ns;
16846 this.fireEvent("selectionchange", this, this.selections);
16850 * Gets a template node.
16851 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16852 * @return {HTMLElement} The node or null if it wasn't found
16854 getNode : function(nodeInfo){
16855 if(typeof nodeInfo == "string"){
16856 return document.getElementById(nodeInfo);
16857 }else if(typeof nodeInfo == "number"){
16858 return this.nodes[nodeInfo];
16864 * Gets a range template nodes.
16865 * @param {Number} startIndex
16866 * @param {Number} endIndex
16867 * @return {Array} An array of nodes
16869 getNodes : function(start, end){
16870 var ns = this.nodes;
16871 start = start || 0;
16872 end = typeof end == "undefined" ? ns.length - 1 : end;
16875 for(var i = start; i <= end; i++){
16879 for(var i = start; i >= end; i--){
16887 * Finds the index of the passed node
16888 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16889 * @return {Number} The index of the node or -1
16891 indexOf : function(node){
16892 node = this.getNode(node);
16893 if(typeof node.nodeIndex == "number"){
16894 return node.nodeIndex;
16896 var ns = this.nodes;
16897 for(var i = 0, len = ns.length; i < len; i++){
16908 * based on jquery fullcalendar
16912 Roo.bootstrap = Roo.bootstrap || {};
16914 * @class Roo.bootstrap.Calendar
16915 * @extends Roo.bootstrap.Component
16916 * Bootstrap Calendar class
16917 * @cfg {Boolean} loadMask (true|false) default false
16918 * @cfg {Object} header generate the user specific header of the calendar, default false
16921 * Create a new Container
16922 * @param {Object} config The config object
16927 Roo.bootstrap.Calendar = function(config){
16928 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16932 * Fires when a date is selected
16933 * @param {DatePicker} this
16934 * @param {Date} date The selected date
16938 * @event monthchange
16939 * Fires when the displayed month changes
16940 * @param {DatePicker} this
16941 * @param {Date} date The selected month
16943 'monthchange': true,
16945 * @event evententer
16946 * Fires when mouse over an event
16947 * @param {Calendar} this
16948 * @param {event} Event
16950 'evententer': true,
16952 * @event eventleave
16953 * Fires when the mouse leaves an
16954 * @param {Calendar} this
16957 'eventleave': true,
16959 * @event eventclick
16960 * Fires when the mouse click an
16961 * @param {Calendar} this
16970 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16973 * @cfg {Number} startDay
16974 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16982 getAutoCreate : function(){
16985 var fc_button = function(name, corner, style, content ) {
16986 return Roo.apply({},{
16988 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16990 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16993 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17004 style : 'width:100%',
17011 cls : 'fc-header-left',
17013 fc_button('prev', 'left', 'arrow', '‹' ),
17014 fc_button('next', 'right', 'arrow', '›' ),
17015 { tag: 'span', cls: 'fc-header-space' },
17016 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17024 cls : 'fc-header-center',
17028 cls: 'fc-header-title',
17031 html : 'month / year'
17039 cls : 'fc-header-right',
17041 /* fc_button('month', 'left', '', 'month' ),
17042 fc_button('week', '', '', 'week' ),
17043 fc_button('day', 'right', '', 'day' )
17055 header = this.header;
17058 var cal_heads = function() {
17060 // fixme - handle this.
17062 for (var i =0; i < Date.dayNames.length; i++) {
17063 var d = Date.dayNames[i];
17066 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17067 html : d.substring(0,3)
17071 ret[0].cls += ' fc-first';
17072 ret[6].cls += ' fc-last';
17075 var cal_cell = function(n) {
17078 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17083 cls: 'fc-day-number',
17087 cls: 'fc-day-content',
17091 style: 'position: relative;' // height: 17px;
17103 var cal_rows = function() {
17106 for (var r = 0; r < 6; r++) {
17113 for (var i =0; i < Date.dayNames.length; i++) {
17114 var d = Date.dayNames[i];
17115 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17118 row.cn[0].cls+=' fc-first';
17119 row.cn[0].cn[0].style = 'min-height:90px';
17120 row.cn[6].cls+=' fc-last';
17124 ret[0].cls += ' fc-first';
17125 ret[4].cls += ' fc-prev-last';
17126 ret[5].cls += ' fc-last';
17133 cls: 'fc-border-separate',
17134 style : 'width:100%',
17142 cls : 'fc-first fc-last',
17160 cls : 'fc-content',
17161 style : "position: relative;",
17164 cls : 'fc-view fc-view-month fc-grid',
17165 style : 'position: relative',
17166 unselectable : 'on',
17169 cls : 'fc-event-container',
17170 style : 'position:absolute;z-index:8;top:0;left:0;'
17188 initEvents : function()
17191 throw "can not find store for calendar";
17197 style: "text-align:center",
17201 style: "background-color:white;width:50%;margin:250 auto",
17205 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17216 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17218 var size = this.el.select('.fc-content', true).first().getSize();
17219 this.maskEl.setSize(size.width, size.height);
17220 this.maskEl.enableDisplayMode("block");
17221 if(!this.loadMask){
17222 this.maskEl.hide();
17225 this.store = Roo.factory(this.store, Roo.data);
17226 this.store.on('load', this.onLoad, this);
17227 this.store.on('beforeload', this.onBeforeLoad, this);
17231 this.cells = this.el.select('.fc-day',true);
17232 //Roo.log(this.cells);
17233 this.textNodes = this.el.query('.fc-day-number');
17234 this.cells.addClassOnOver('fc-state-hover');
17236 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17237 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17238 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17239 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17241 this.on('monthchange', this.onMonthChange, this);
17243 this.update(new Date().clearTime());
17246 resize : function() {
17247 var sz = this.el.getSize();
17249 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17250 this.el.select('.fc-day-content div',true).setHeight(34);
17255 showPrevMonth : function(e){
17256 this.update(this.activeDate.add("mo", -1));
17258 showToday : function(e){
17259 this.update(new Date().clearTime());
17262 showNextMonth : function(e){
17263 this.update(this.activeDate.add("mo", 1));
17267 showPrevYear : function(){
17268 this.update(this.activeDate.add("y", -1));
17272 showNextYear : function(){
17273 this.update(this.activeDate.add("y", 1));
17278 update : function(date)
17280 var vd = this.activeDate;
17281 this.activeDate = date;
17282 // if(vd && this.el){
17283 // var t = date.getTime();
17284 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17285 // Roo.log('using add remove');
17287 // this.fireEvent('monthchange', this, date);
17289 // this.cells.removeClass("fc-state-highlight");
17290 // this.cells.each(function(c){
17291 // if(c.dateValue == t){
17292 // c.addClass("fc-state-highlight");
17293 // setTimeout(function(){
17294 // try{c.dom.firstChild.focus();}catch(e){}
17304 var days = date.getDaysInMonth();
17306 var firstOfMonth = date.getFirstDateOfMonth();
17307 var startingPos = firstOfMonth.getDay()-this.startDay;
17309 if(startingPos < this.startDay){
17313 var pm = date.add(Date.MONTH, -1);
17314 var prevStart = pm.getDaysInMonth()-startingPos;
17316 this.cells = this.el.select('.fc-day',true);
17317 this.textNodes = this.el.query('.fc-day-number');
17318 this.cells.addClassOnOver('fc-state-hover');
17320 var cells = this.cells.elements;
17321 var textEls = this.textNodes;
17323 Roo.each(cells, function(cell){
17324 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17327 days += startingPos;
17329 // convert everything to numbers so it's fast
17330 var day = 86400000;
17331 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17334 //Roo.log(prevStart);
17336 var today = new Date().clearTime().getTime();
17337 var sel = date.clearTime().getTime();
17338 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17339 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17340 var ddMatch = this.disabledDatesRE;
17341 var ddText = this.disabledDatesText;
17342 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17343 var ddaysText = this.disabledDaysText;
17344 var format = this.format;
17346 var setCellClass = function(cal, cell){
17350 //Roo.log('set Cell Class');
17352 var t = d.getTime();
17356 cell.dateValue = t;
17358 cell.className += " fc-today";
17359 cell.className += " fc-state-highlight";
17360 cell.title = cal.todayText;
17363 // disable highlight in other month..
17364 //cell.className += " fc-state-highlight";
17369 cell.className = " fc-state-disabled";
17370 cell.title = cal.minText;
17374 cell.className = " fc-state-disabled";
17375 cell.title = cal.maxText;
17379 if(ddays.indexOf(d.getDay()) != -1){
17380 cell.title = ddaysText;
17381 cell.className = " fc-state-disabled";
17384 if(ddMatch && format){
17385 var fvalue = d.dateFormat(format);
17386 if(ddMatch.test(fvalue)){
17387 cell.title = ddText.replace("%0", fvalue);
17388 cell.className = " fc-state-disabled";
17392 if (!cell.initialClassName) {
17393 cell.initialClassName = cell.dom.className;
17396 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17401 for(; i < startingPos; i++) {
17402 textEls[i].innerHTML = (++prevStart);
17403 d.setDate(d.getDate()+1);
17405 cells[i].className = "fc-past fc-other-month";
17406 setCellClass(this, cells[i]);
17411 for(; i < days; i++){
17412 intDay = i - startingPos + 1;
17413 textEls[i].innerHTML = (intDay);
17414 d.setDate(d.getDate()+1);
17416 cells[i].className = ''; // "x-date-active";
17417 setCellClass(this, cells[i]);
17421 for(; i < 42; i++) {
17422 textEls[i].innerHTML = (++extraDays);
17423 d.setDate(d.getDate()+1);
17425 cells[i].className = "fc-future fc-other-month";
17426 setCellClass(this, cells[i]);
17429 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17431 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17433 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17434 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17436 if(totalRows != 6){
17437 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17438 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17441 this.fireEvent('monthchange', this, date);
17445 if(!this.internalRender){
17446 var main = this.el.dom.firstChild;
17447 var w = main.offsetWidth;
17448 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17449 Roo.fly(main).setWidth(w);
17450 this.internalRender = true;
17451 // opera does not respect the auto grow header center column
17452 // then, after it gets a width opera refuses to recalculate
17453 // without a second pass
17454 if(Roo.isOpera && !this.secondPass){
17455 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17456 this.secondPass = true;
17457 this.update.defer(10, this, [date]);
17464 findCell : function(dt) {
17465 dt = dt.clearTime().getTime();
17467 this.cells.each(function(c){
17468 //Roo.log("check " +c.dateValue + '?=' + dt);
17469 if(c.dateValue == dt){
17479 findCells : function(ev) {
17480 var s = ev.start.clone().clearTime().getTime();
17482 var e= ev.end.clone().clearTime().getTime();
17485 this.cells.each(function(c){
17486 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17488 if(c.dateValue > e){
17491 if(c.dateValue < s){
17500 // findBestRow: function(cells)
17504 // for (var i =0 ; i < cells.length;i++) {
17505 // ret = Math.max(cells[i].rows || 0,ret);
17512 addItem : function(ev)
17514 // look for vertical location slot in
17515 var cells = this.findCells(ev);
17517 // ev.row = this.findBestRow(cells);
17519 // work out the location.
17523 for(var i =0; i < cells.length; i++) {
17525 cells[i].row = cells[0].row;
17528 cells[i].row = cells[i].row + 1;
17538 if (crow.start.getY() == cells[i].getY()) {
17540 crow.end = cells[i];
17557 cells[0].events.push(ev);
17559 this.calevents.push(ev);
17562 clearEvents: function() {
17564 if(!this.calevents){
17568 Roo.each(this.cells.elements, function(c){
17574 Roo.each(this.calevents, function(e) {
17575 Roo.each(e.els, function(el) {
17576 el.un('mouseenter' ,this.onEventEnter, this);
17577 el.un('mouseleave' ,this.onEventLeave, this);
17582 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17588 renderEvents: function()
17592 this.cells.each(function(c) {
17601 if(c.row != c.events.length){
17602 r = 4 - (4 - (c.row - c.events.length));
17605 c.events = ev.slice(0, r);
17606 c.more = ev.slice(r);
17608 if(c.more.length && c.more.length == 1){
17609 c.events.push(c.more.pop());
17612 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17616 this.cells.each(function(c) {
17618 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17621 for (var e = 0; e < c.events.length; e++){
17622 var ev = c.events[e];
17623 var rows = ev.rows;
17625 for(var i = 0; i < rows.length; i++) {
17627 // how many rows should it span..
17630 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17631 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17633 unselectable : "on",
17636 cls: 'fc-event-inner',
17640 // cls: 'fc-event-time',
17641 // html : cells.length > 1 ? '' : ev.time
17645 cls: 'fc-event-title',
17646 html : String.format('{0}', ev.title)
17653 cls: 'ui-resizable-handle ui-resizable-e',
17654 html : '  '
17661 cfg.cls += ' fc-event-start';
17663 if ((i+1) == rows.length) {
17664 cfg.cls += ' fc-event-end';
17667 var ctr = _this.el.select('.fc-event-container',true).first();
17668 var cg = ctr.createChild(cfg);
17670 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17671 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17673 var r = (c.more.length) ? 1 : 0;
17674 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17675 cg.setWidth(ebox.right - sbox.x -2);
17677 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17678 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17679 cg.on('click', _this.onEventClick, _this, ev);
17690 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17691 style : 'position: absolute',
17692 unselectable : "on",
17695 cls: 'fc-event-inner',
17699 cls: 'fc-event-title',
17707 cls: 'ui-resizable-handle ui-resizable-e',
17708 html : '  '
17714 var ctr = _this.el.select('.fc-event-container',true).first();
17715 var cg = ctr.createChild(cfg);
17717 var sbox = c.select('.fc-day-content',true).first().getBox();
17718 var ebox = c.select('.fc-day-content',true).first().getBox();
17720 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17721 cg.setWidth(ebox.right - sbox.x -2);
17723 cg.on('click', _this.onMoreEventClick, _this, c.more);
17733 onEventEnter: function (e, el,event,d) {
17734 this.fireEvent('evententer', this, el, event);
17737 onEventLeave: function (e, el,event,d) {
17738 this.fireEvent('eventleave', this, el, event);
17741 onEventClick: function (e, el,event,d) {
17742 this.fireEvent('eventclick', this, el, event);
17745 onMonthChange: function () {
17749 onMoreEventClick: function(e, el, more)
17753 this.calpopover.placement = 'right';
17754 this.calpopover.setTitle('More');
17756 this.calpopover.setContent('');
17758 var ctr = this.calpopover.el.select('.popover-content', true).first();
17760 Roo.each(more, function(m){
17762 cls : 'fc-event-hori fc-event-draggable',
17765 var cg = ctr.createChild(cfg);
17767 cg.on('click', _this.onEventClick, _this, m);
17770 this.calpopover.show(el);
17775 onLoad: function ()
17777 this.calevents = [];
17780 if(this.store.getCount() > 0){
17781 this.store.data.each(function(d){
17784 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17785 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17786 time : d.data.start_time,
17787 title : d.data.title,
17788 description : d.data.description,
17789 venue : d.data.venue
17794 this.renderEvents();
17796 if(this.calevents.length && this.loadMask){
17797 this.maskEl.hide();
17801 onBeforeLoad: function()
17803 this.clearEvents();
17805 this.maskEl.show();
17819 * @class Roo.bootstrap.Popover
17820 * @extends Roo.bootstrap.Component
17821 * Bootstrap Popover class
17822 * @cfg {String} html contents of the popover (or false to use children..)
17823 * @cfg {String} title of popover (or false to hide)
17824 * @cfg {String} placement how it is placed
17825 * @cfg {String} trigger click || hover (or false to trigger manually)
17826 * @cfg {String} over what (parent or false to trigger manually.)
17827 * @cfg {Number} delay - delay before showing
17830 * Create a new Popover
17831 * @param {Object} config The config object
17834 Roo.bootstrap.Popover = function(config){
17835 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17841 * After the popover show
17843 * @param {Roo.bootstrap.Popover} this
17848 * After the popover hide
17850 * @param {Roo.bootstrap.Popover} this
17856 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17858 title: 'Fill in a title',
17861 placement : 'right',
17862 trigger : 'hover', // hover
17868 can_build_overlaid : false,
17870 getChildContainer : function()
17872 return this.el.select('.popover-content',true).first();
17875 getAutoCreate : function(){
17878 cls : 'popover roo-dynamic',
17879 style: 'display:block',
17885 cls : 'popover-inner',
17889 cls: 'popover-title popover-header',
17893 cls : 'popover-content popover-body',
17904 setTitle: function(str)
17907 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17909 setContent: function(str)
17912 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17914 // as it get's added to the bottom of the page.
17915 onRender : function(ct, position)
17917 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17919 var cfg = Roo.apply({}, this.getAutoCreate());
17923 cfg.cls += ' ' + this.cls;
17926 cfg.style = this.style;
17928 //Roo.log("adding to ");
17929 this.el = Roo.get(document.body).createChild(cfg, position);
17930 // Roo.log(this.el);
17935 initEvents : function()
17937 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17938 this.el.enableDisplayMode('block');
17940 if (this.over === false) {
17943 if (this.triggers === false) {
17946 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17947 var triggers = this.trigger ? this.trigger.split(' ') : [];
17948 Roo.each(triggers, function(trigger) {
17950 if (trigger == 'click') {
17951 on_el.on('click', this.toggle, this);
17952 } else if (trigger != 'manual') {
17953 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17954 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17956 on_el.on(eventIn ,this.enter, this);
17957 on_el.on(eventOut, this.leave, this);
17968 toggle : function () {
17969 this.hoverState == 'in' ? this.leave() : this.enter();
17972 enter : function () {
17974 clearTimeout(this.timeout);
17976 this.hoverState = 'in';
17978 if (!this.delay || !this.delay.show) {
17983 this.timeout = setTimeout(function () {
17984 if (_t.hoverState == 'in') {
17987 }, this.delay.show)
17990 leave : function() {
17991 clearTimeout(this.timeout);
17993 this.hoverState = 'out';
17995 if (!this.delay || !this.delay.hide) {
18000 this.timeout = setTimeout(function () {
18001 if (_t.hoverState == 'out') {
18004 }, this.delay.hide)
18007 show : function (on_el)
18010 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18014 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18015 if (this.html !== false) {
18016 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18018 this.el.removeClass([
18019 'fade','top','bottom', 'left', 'right','in',
18020 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18022 if (!this.title.length) {
18023 this.el.select('.popover-title',true).hide();
18026 var placement = typeof this.placement == 'function' ?
18027 this.placement.call(this, this.el, on_el) :
18030 var autoToken = /\s?auto?\s?/i;
18031 var autoPlace = autoToken.test(placement);
18033 placement = placement.replace(autoToken, '') || 'top';
18037 //this.el.setXY([0,0]);
18039 this.el.dom.style.display='block';
18040 this.el.addClass(placement);
18042 //this.el.appendTo(on_el);
18044 var p = this.getPosition();
18045 var box = this.el.getBox();
18050 var align = Roo.bootstrap.Popover.alignment[placement];
18053 this.el.alignTo(on_el, align[0],align[1]);
18054 //var arrow = this.el.select('.arrow',true).first();
18055 //arrow.set(align[2],
18057 this.el.addClass('in');
18060 if (this.el.hasClass('fade')) {
18064 this.hoverState = 'in';
18066 this.fireEvent('show', this);
18071 this.el.setXY([0,0]);
18072 this.el.removeClass('in');
18074 this.hoverState = null;
18076 this.fireEvent('hide', this);
18081 Roo.bootstrap.Popover.alignment = {
18082 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18083 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18084 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18085 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18096 * @class Roo.bootstrap.Progress
18097 * @extends Roo.bootstrap.Component
18098 * Bootstrap Progress class
18099 * @cfg {Boolean} striped striped of the progress bar
18100 * @cfg {Boolean} active animated of the progress bar
18104 * Create a new Progress
18105 * @param {Object} config The config object
18108 Roo.bootstrap.Progress = function(config){
18109 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18112 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18117 getAutoCreate : function(){
18125 cfg.cls += ' progress-striped';
18129 cfg.cls += ' active';
18148 * @class Roo.bootstrap.ProgressBar
18149 * @extends Roo.bootstrap.Component
18150 * Bootstrap ProgressBar class
18151 * @cfg {Number} aria_valuenow aria-value now
18152 * @cfg {Number} aria_valuemin aria-value min
18153 * @cfg {Number} aria_valuemax aria-value max
18154 * @cfg {String} label label for the progress bar
18155 * @cfg {String} panel (success | info | warning | danger )
18156 * @cfg {String} role role of the progress bar
18157 * @cfg {String} sr_only text
18161 * Create a new ProgressBar
18162 * @param {Object} config The config object
18165 Roo.bootstrap.ProgressBar = function(config){
18166 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18169 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18173 aria_valuemax : 100,
18179 getAutoCreate : function()
18184 cls: 'progress-bar',
18185 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18197 cfg.role = this.role;
18200 if(this.aria_valuenow){
18201 cfg['aria-valuenow'] = this.aria_valuenow;
18204 if(this.aria_valuemin){
18205 cfg['aria-valuemin'] = this.aria_valuemin;
18208 if(this.aria_valuemax){
18209 cfg['aria-valuemax'] = this.aria_valuemax;
18212 if(this.label && !this.sr_only){
18213 cfg.html = this.label;
18217 cfg.cls += ' progress-bar-' + this.panel;
18223 update : function(aria_valuenow)
18225 this.aria_valuenow = aria_valuenow;
18227 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18242 * @class Roo.bootstrap.TabGroup
18243 * @extends Roo.bootstrap.Column
18244 * Bootstrap Column class
18245 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18246 * @cfg {Boolean} carousel true to make the group behave like a carousel
18247 * @cfg {Boolean} bullets show bullets for the panels
18248 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18249 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18250 * @cfg {Boolean} showarrow (true|false) show arrow default true
18253 * Create a new TabGroup
18254 * @param {Object} config The config object
18257 Roo.bootstrap.TabGroup = function(config){
18258 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18260 this.navId = Roo.id();
18263 Roo.bootstrap.TabGroup.register(this);
18267 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18270 transition : false,
18275 slideOnTouch : false,
18278 getAutoCreate : function()
18280 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18282 cfg.cls += ' tab-content';
18284 if (this.carousel) {
18285 cfg.cls += ' carousel slide';
18288 cls : 'carousel-inner',
18292 if(this.bullets && !Roo.isTouch){
18295 cls : 'carousel-bullets',
18299 if(this.bullets_cls){
18300 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18307 cfg.cn[0].cn.push(bullets);
18310 if(this.showarrow){
18311 cfg.cn[0].cn.push({
18313 class : 'carousel-arrow',
18317 class : 'carousel-prev',
18321 class : 'fa fa-chevron-left'
18327 class : 'carousel-next',
18331 class : 'fa fa-chevron-right'
18344 initEvents: function()
18346 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18347 // this.el.on("touchstart", this.onTouchStart, this);
18350 if(this.autoslide){
18353 this.slideFn = window.setInterval(function() {
18354 _this.showPanelNext();
18358 if(this.showarrow){
18359 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18360 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18366 // onTouchStart : function(e, el, o)
18368 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18372 // this.showPanelNext();
18376 getChildContainer : function()
18378 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18382 * register a Navigation item
18383 * @param {Roo.bootstrap.NavItem} the navitem to add
18385 register : function(item)
18387 this.tabs.push( item);
18388 item.navId = this.navId; // not really needed..
18393 getActivePanel : function()
18396 Roo.each(this.tabs, function(t) {
18406 getPanelByName : function(n)
18409 Roo.each(this.tabs, function(t) {
18410 if (t.tabId == n) {
18418 indexOfPanel : function(p)
18421 Roo.each(this.tabs, function(t,i) {
18422 if (t.tabId == p.tabId) {
18431 * show a specific panel
18432 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18433 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18435 showPanel : function (pan)
18437 if(this.transition || typeof(pan) == 'undefined'){
18438 Roo.log("waiting for the transitionend");
18442 if (typeof(pan) == 'number') {
18443 pan = this.tabs[pan];
18446 if (typeof(pan) == 'string') {
18447 pan = this.getPanelByName(pan);
18450 var cur = this.getActivePanel();
18453 Roo.log('pan or acitve pan is undefined');
18457 if (pan.tabId == this.getActivePanel().tabId) {
18461 if (false === cur.fireEvent('beforedeactivate')) {
18465 if(this.bullets > 0 && !Roo.isTouch){
18466 this.setActiveBullet(this.indexOfPanel(pan));
18469 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18471 //class="carousel-item carousel-item-next carousel-item-left"
18473 this.transition = true;
18474 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18475 var lr = dir == 'next' ? 'left' : 'right';
18476 pan.el.addClass(dir); // or prev
18477 pan.el.addClass('carousel-item-' + dir); // or prev
18478 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18479 cur.el.addClass(lr); // or right
18480 pan.el.addClass(lr);
18481 cur.el.addClass('carousel-item-' +lr); // or right
18482 pan.el.addClass('carousel-item-' +lr);
18486 cur.el.on('transitionend', function() {
18487 Roo.log("trans end?");
18489 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18490 pan.setActive(true);
18492 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18493 cur.setActive(false);
18495 _this.transition = false;
18497 }, this, { single: true } );
18502 cur.setActive(false);
18503 pan.setActive(true);
18508 showPanelNext : function()
18510 var i = this.indexOfPanel(this.getActivePanel());
18512 if (i >= this.tabs.length - 1 && !this.autoslide) {
18516 if (i >= this.tabs.length - 1 && this.autoslide) {
18520 this.showPanel(this.tabs[i+1]);
18523 showPanelPrev : function()
18525 var i = this.indexOfPanel(this.getActivePanel());
18527 if (i < 1 && !this.autoslide) {
18531 if (i < 1 && this.autoslide) {
18532 i = this.tabs.length;
18535 this.showPanel(this.tabs[i-1]);
18539 addBullet: function()
18541 if(!this.bullets || Roo.isTouch){
18544 var ctr = this.el.select('.carousel-bullets',true).first();
18545 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18546 var bullet = ctr.createChild({
18547 cls : 'bullet bullet-' + i
18548 },ctr.dom.lastChild);
18553 bullet.on('click', (function(e, el, o, ii, t){
18555 e.preventDefault();
18557 this.showPanel(ii);
18559 if(this.autoslide && this.slideFn){
18560 clearInterval(this.slideFn);
18561 this.slideFn = window.setInterval(function() {
18562 _this.showPanelNext();
18566 }).createDelegate(this, [i, bullet], true));
18571 setActiveBullet : function(i)
18577 Roo.each(this.el.select('.bullet', true).elements, function(el){
18578 el.removeClass('selected');
18581 var bullet = this.el.select('.bullet-' + i, true).first();
18587 bullet.addClass('selected');
18598 Roo.apply(Roo.bootstrap.TabGroup, {
18602 * register a Navigation Group
18603 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18605 register : function(navgrp)
18607 this.groups[navgrp.navId] = navgrp;
18611 * fetch a Navigation Group based on the navigation ID
18612 * if one does not exist , it will get created.
18613 * @param {string} the navgroup to add
18614 * @returns {Roo.bootstrap.NavGroup} the navgroup
18616 get: function(navId) {
18617 if (typeof(this.groups[navId]) == 'undefined') {
18618 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18620 return this.groups[navId] ;
18635 * @class Roo.bootstrap.TabPanel
18636 * @extends Roo.bootstrap.Component
18637 * Bootstrap TabPanel class
18638 * @cfg {Boolean} active panel active
18639 * @cfg {String} html panel content
18640 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18641 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18642 * @cfg {String} href click to link..
18646 * Create a new TabPanel
18647 * @param {Object} config The config object
18650 Roo.bootstrap.TabPanel = function(config){
18651 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18655 * Fires when the active status changes
18656 * @param {Roo.bootstrap.TabPanel} this
18657 * @param {Boolean} state the new state
18662 * @event beforedeactivate
18663 * Fires before a tab is de-activated - can be used to do validation on a form.
18664 * @param {Roo.bootstrap.TabPanel} this
18665 * @return {Boolean} false if there is an error
18668 'beforedeactivate': true
18671 this.tabId = this.tabId || Roo.id();
18675 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18683 getAutoCreate : function(){
18688 // item is needed for carousel - not sure if it has any effect otherwise
18689 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18690 html: this.html || ''
18694 cfg.cls += ' active';
18698 cfg.tabId = this.tabId;
18706 initEvents: function()
18708 var p = this.parent();
18710 this.navId = this.navId || p.navId;
18712 if (typeof(this.navId) != 'undefined') {
18713 // not really needed.. but just in case.. parent should be a NavGroup.
18714 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18718 var i = tg.tabs.length - 1;
18720 if(this.active && tg.bullets > 0 && i < tg.bullets){
18721 tg.setActiveBullet(i);
18725 this.el.on('click', this.onClick, this);
18728 this.el.on("touchstart", this.onTouchStart, this);
18729 this.el.on("touchmove", this.onTouchMove, this);
18730 this.el.on("touchend", this.onTouchEnd, this);
18735 onRender : function(ct, position)
18737 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18740 setActive : function(state)
18742 Roo.log("panel - set active " + this.tabId + "=" + state);
18744 this.active = state;
18746 this.el.removeClass('active');
18748 } else if (!this.el.hasClass('active')) {
18749 this.el.addClass('active');
18752 this.fireEvent('changed', this, state);
18755 onClick : function(e)
18757 e.preventDefault();
18759 if(!this.href.length){
18763 window.location.href = this.href;
18772 onTouchStart : function(e)
18774 this.swiping = false;
18776 this.startX = e.browserEvent.touches[0].clientX;
18777 this.startY = e.browserEvent.touches[0].clientY;
18780 onTouchMove : function(e)
18782 this.swiping = true;
18784 this.endX = e.browserEvent.touches[0].clientX;
18785 this.endY = e.browserEvent.touches[0].clientY;
18788 onTouchEnd : function(e)
18795 var tabGroup = this.parent();
18797 if(this.endX > this.startX){ // swiping right
18798 tabGroup.showPanelPrev();
18802 if(this.startX > this.endX){ // swiping left
18803 tabGroup.showPanelNext();
18822 * @class Roo.bootstrap.DateField
18823 * @extends Roo.bootstrap.Input
18824 * Bootstrap DateField class
18825 * @cfg {Number} weekStart default 0
18826 * @cfg {String} viewMode default empty, (months|years)
18827 * @cfg {String} minViewMode default empty, (months|years)
18828 * @cfg {Number} startDate default -Infinity
18829 * @cfg {Number} endDate default Infinity
18830 * @cfg {Boolean} todayHighlight default false
18831 * @cfg {Boolean} todayBtn default false
18832 * @cfg {Boolean} calendarWeeks default false
18833 * @cfg {Object} daysOfWeekDisabled default empty
18834 * @cfg {Boolean} singleMode default false (true | false)
18836 * @cfg {Boolean} keyboardNavigation default true
18837 * @cfg {String} language default en
18840 * Create a new DateField
18841 * @param {Object} config The config object
18844 Roo.bootstrap.DateField = function(config){
18845 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18849 * Fires when this field show.
18850 * @param {Roo.bootstrap.DateField} this
18851 * @param {Mixed} date The date value
18856 * Fires when this field hide.
18857 * @param {Roo.bootstrap.DateField} this
18858 * @param {Mixed} date The date value
18863 * Fires when select a date.
18864 * @param {Roo.bootstrap.DateField} this
18865 * @param {Mixed} date The date value
18869 * @event beforeselect
18870 * Fires when before select a date.
18871 * @param {Roo.bootstrap.DateField} this
18872 * @param {Mixed} date The date value
18874 beforeselect : true
18878 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18881 * @cfg {String} format
18882 * The default date format string which can be overriden for localization support. The format must be
18883 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18887 * @cfg {String} altFormats
18888 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18889 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18891 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18899 todayHighlight : false,
18905 keyboardNavigation: true,
18907 calendarWeeks: false,
18909 startDate: -Infinity,
18913 daysOfWeekDisabled: [],
18917 singleMode : false,
18919 UTCDate: function()
18921 return new Date(Date.UTC.apply(Date, arguments));
18924 UTCToday: function()
18926 var today = new Date();
18927 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18930 getDate: function() {
18931 var d = this.getUTCDate();
18932 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18935 getUTCDate: function() {
18939 setDate: function(d) {
18940 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18943 setUTCDate: function(d) {
18945 this.setValue(this.formatDate(this.date));
18948 onRender: function(ct, position)
18951 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18953 this.language = this.language || 'en';
18954 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18955 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18957 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18958 this.format = this.format || 'm/d/y';
18959 this.isInline = false;
18960 this.isInput = true;
18961 this.component = this.el.select('.add-on', true).first() || false;
18962 this.component = (this.component && this.component.length === 0) ? false : this.component;
18963 this.hasInput = this.component && this.inputEl().length;
18965 if (typeof(this.minViewMode === 'string')) {
18966 switch (this.minViewMode) {
18968 this.minViewMode = 1;
18971 this.minViewMode = 2;
18974 this.minViewMode = 0;
18979 if (typeof(this.viewMode === 'string')) {
18980 switch (this.viewMode) {
18993 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18995 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18997 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18999 this.picker().on('mousedown', this.onMousedown, this);
19000 this.picker().on('click', this.onClick, this);
19002 this.picker().addClass('datepicker-dropdown');
19004 this.startViewMode = this.viewMode;
19006 if(this.singleMode){
19007 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19008 v.setVisibilityMode(Roo.Element.DISPLAY);
19012 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19013 v.setStyle('width', '189px');
19017 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19018 if(!this.calendarWeeks){
19023 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19024 v.attr('colspan', function(i, val){
19025 return parseInt(val) + 1;
19030 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19032 this.setStartDate(this.startDate);
19033 this.setEndDate(this.endDate);
19035 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19042 if(this.isInline) {
19047 picker : function()
19049 return this.pickerEl;
19050 // return this.el.select('.datepicker', true).first();
19053 fillDow: function()
19055 var dowCnt = this.weekStart;
19064 if(this.calendarWeeks){
19072 while (dowCnt < this.weekStart + 7) {
19076 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19080 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19083 fillMonths: function()
19086 var months = this.picker().select('>.datepicker-months td', true).first();
19088 months.dom.innerHTML = '';
19094 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19097 months.createChild(month);
19104 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;
19106 if (this.date < this.startDate) {
19107 this.viewDate = new Date(this.startDate);
19108 } else if (this.date > this.endDate) {
19109 this.viewDate = new Date(this.endDate);
19111 this.viewDate = new Date(this.date);
19119 var d = new Date(this.viewDate),
19120 year = d.getUTCFullYear(),
19121 month = d.getUTCMonth(),
19122 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19123 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19124 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19125 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19126 currentDate = this.date && this.date.valueOf(),
19127 today = this.UTCToday();
19129 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19131 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19133 // this.picker.select('>tfoot th.today').
19134 // .text(dates[this.language].today)
19135 // .toggle(this.todayBtn !== false);
19137 this.updateNavArrows();
19140 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19142 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19144 prevMonth.setUTCDate(day);
19146 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19148 var nextMonth = new Date(prevMonth);
19150 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19152 nextMonth = nextMonth.valueOf();
19154 var fillMonths = false;
19156 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19158 while(prevMonth.valueOf() <= nextMonth) {
19161 if (prevMonth.getUTCDay() === this.weekStart) {
19163 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19171 if(this.calendarWeeks){
19172 // ISO 8601: First week contains first thursday.
19173 // ISO also states week starts on Monday, but we can be more abstract here.
19175 // Start of current week: based on weekstart/current date
19176 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19177 // Thursday of this week
19178 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19179 // First Thursday of year, year from thursday
19180 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19181 // Calendar week: ms between thursdays, div ms per day, div 7 days
19182 calWeek = (th - yth) / 864e5 / 7 + 1;
19184 fillMonths.cn.push({
19192 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19194 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19197 if (this.todayHighlight &&
19198 prevMonth.getUTCFullYear() == today.getFullYear() &&
19199 prevMonth.getUTCMonth() == today.getMonth() &&
19200 prevMonth.getUTCDate() == today.getDate()) {
19201 clsName += ' today';
19204 if (currentDate && prevMonth.valueOf() === currentDate) {
19205 clsName += ' active';
19208 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19209 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19210 clsName += ' disabled';
19213 fillMonths.cn.push({
19215 cls: 'day ' + clsName,
19216 html: prevMonth.getDate()
19219 prevMonth.setDate(prevMonth.getDate()+1);
19222 var currentYear = this.date && this.date.getUTCFullYear();
19223 var currentMonth = this.date && this.date.getUTCMonth();
19225 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19227 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19228 v.removeClass('active');
19230 if(currentYear === year && k === currentMonth){
19231 v.addClass('active');
19234 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19235 v.addClass('disabled');
19241 year = parseInt(year/10, 10) * 10;
19243 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19245 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19248 for (var i = -1; i < 11; i++) {
19249 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19251 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19259 showMode: function(dir)
19262 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19265 Roo.each(this.picker().select('>div',true).elements, function(v){
19266 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19269 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19274 if(this.isInline) {
19278 this.picker().removeClass(['bottom', 'top']);
19280 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19282 * place to the top of element!
19286 this.picker().addClass('top');
19287 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19292 this.picker().addClass('bottom');
19294 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19297 parseDate : function(value)
19299 if(!value || value instanceof Date){
19302 var v = Date.parseDate(value, this.format);
19303 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19304 v = Date.parseDate(value, 'Y-m-d');
19306 if(!v && this.altFormats){
19307 if(!this.altFormatsArray){
19308 this.altFormatsArray = this.altFormats.split("|");
19310 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19311 v = Date.parseDate(value, this.altFormatsArray[i]);
19317 formatDate : function(date, fmt)
19319 return (!date || !(date instanceof Date)) ?
19320 date : date.dateFormat(fmt || this.format);
19323 onFocus : function()
19325 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19329 onBlur : function()
19331 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19333 var d = this.inputEl().getValue();
19340 showPopup : function()
19342 this.picker().show();
19346 this.fireEvent('showpopup', this, this.date);
19349 hidePopup : function()
19351 if(this.isInline) {
19354 this.picker().hide();
19355 this.viewMode = this.startViewMode;
19358 this.fireEvent('hidepopup', this, this.date);
19362 onMousedown: function(e)
19364 e.stopPropagation();
19365 e.preventDefault();
19370 Roo.bootstrap.DateField.superclass.keyup.call(this);
19374 setValue: function(v)
19376 if(this.fireEvent('beforeselect', this, v) !== false){
19377 var d = new Date(this.parseDate(v) ).clearTime();
19379 if(isNaN(d.getTime())){
19380 this.date = this.viewDate = '';
19381 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19385 v = this.formatDate(d);
19387 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19389 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19393 this.fireEvent('select', this, this.date);
19397 getValue: function()
19399 return this.formatDate(this.date);
19402 fireKey: function(e)
19404 if (!this.picker().isVisible()){
19405 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19411 var dateChanged = false,
19413 newDate, newViewDate;
19418 e.preventDefault();
19422 if (!this.keyboardNavigation) {
19425 dir = e.keyCode == 37 ? -1 : 1;
19428 newDate = this.moveYear(this.date, dir);
19429 newViewDate = this.moveYear(this.viewDate, dir);
19430 } else if (e.shiftKey){
19431 newDate = this.moveMonth(this.date, dir);
19432 newViewDate = this.moveMonth(this.viewDate, dir);
19434 newDate = new Date(this.date);
19435 newDate.setUTCDate(this.date.getUTCDate() + dir);
19436 newViewDate = new Date(this.viewDate);
19437 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19439 if (this.dateWithinRange(newDate)){
19440 this.date = newDate;
19441 this.viewDate = newViewDate;
19442 this.setValue(this.formatDate(this.date));
19444 e.preventDefault();
19445 dateChanged = true;
19450 if (!this.keyboardNavigation) {
19453 dir = e.keyCode == 38 ? -1 : 1;
19455 newDate = this.moveYear(this.date, dir);
19456 newViewDate = this.moveYear(this.viewDate, dir);
19457 } else if (e.shiftKey){
19458 newDate = this.moveMonth(this.date, dir);
19459 newViewDate = this.moveMonth(this.viewDate, dir);
19461 newDate = new Date(this.date);
19462 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19463 newViewDate = new Date(this.viewDate);
19464 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19466 if (this.dateWithinRange(newDate)){
19467 this.date = newDate;
19468 this.viewDate = newViewDate;
19469 this.setValue(this.formatDate(this.date));
19471 e.preventDefault();
19472 dateChanged = true;
19476 this.setValue(this.formatDate(this.date));
19478 e.preventDefault();
19481 this.setValue(this.formatDate(this.date));
19495 onClick: function(e)
19497 e.stopPropagation();
19498 e.preventDefault();
19500 var target = e.getTarget();
19502 if(target.nodeName.toLowerCase() === 'i'){
19503 target = Roo.get(target).dom.parentNode;
19506 var nodeName = target.nodeName;
19507 var className = target.className;
19508 var html = target.innerHTML;
19509 //Roo.log(nodeName);
19511 switch(nodeName.toLowerCase()) {
19513 switch(className) {
19519 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19520 switch(this.viewMode){
19522 this.viewDate = this.moveMonth(this.viewDate, dir);
19526 this.viewDate = this.moveYear(this.viewDate, dir);
19532 var date = new Date();
19533 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19535 this.setValue(this.formatDate(this.date));
19542 if (className.indexOf('disabled') < 0) {
19543 this.viewDate.setUTCDate(1);
19544 if (className.indexOf('month') > -1) {
19545 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19547 var year = parseInt(html, 10) || 0;
19548 this.viewDate.setUTCFullYear(year);
19552 if(this.singleMode){
19553 this.setValue(this.formatDate(this.viewDate));
19564 //Roo.log(className);
19565 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19566 var day = parseInt(html, 10) || 1;
19567 var year = this.viewDate.getUTCFullYear(),
19568 month = this.viewDate.getUTCMonth();
19570 if (className.indexOf('old') > -1) {
19577 } else if (className.indexOf('new') > -1) {
19585 //Roo.log([year,month,day]);
19586 this.date = this.UTCDate(year, month, day,0,0,0,0);
19587 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19589 //Roo.log(this.formatDate(this.date));
19590 this.setValue(this.formatDate(this.date));
19597 setStartDate: function(startDate)
19599 this.startDate = startDate || -Infinity;
19600 if (this.startDate !== -Infinity) {
19601 this.startDate = this.parseDate(this.startDate);
19604 this.updateNavArrows();
19607 setEndDate: function(endDate)
19609 this.endDate = endDate || Infinity;
19610 if (this.endDate !== Infinity) {
19611 this.endDate = this.parseDate(this.endDate);
19614 this.updateNavArrows();
19617 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19619 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19620 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19621 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19623 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19624 return parseInt(d, 10);
19627 this.updateNavArrows();
19630 updateNavArrows: function()
19632 if(this.singleMode){
19636 var d = new Date(this.viewDate),
19637 year = d.getUTCFullYear(),
19638 month = d.getUTCMonth();
19640 Roo.each(this.picker().select('.prev', true).elements, function(v){
19642 switch (this.viewMode) {
19645 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19651 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19658 Roo.each(this.picker().select('.next', true).elements, function(v){
19660 switch (this.viewMode) {
19663 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19669 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19677 moveMonth: function(date, dir)
19682 var new_date = new Date(date.valueOf()),
19683 day = new_date.getUTCDate(),
19684 month = new_date.getUTCMonth(),
19685 mag = Math.abs(dir),
19687 dir = dir > 0 ? 1 : -1;
19690 // If going back one month, make sure month is not current month
19691 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19693 return new_date.getUTCMonth() == month;
19695 // If going forward one month, make sure month is as expected
19696 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19698 return new_date.getUTCMonth() != new_month;
19700 new_month = month + dir;
19701 new_date.setUTCMonth(new_month);
19702 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19703 if (new_month < 0 || new_month > 11) {
19704 new_month = (new_month + 12) % 12;
19707 // For magnitudes >1, move one month at a time...
19708 for (var i=0; i<mag; i++) {
19709 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19710 new_date = this.moveMonth(new_date, dir);
19712 // ...then reset the day, keeping it in the new month
19713 new_month = new_date.getUTCMonth();
19714 new_date.setUTCDate(day);
19716 return new_month != new_date.getUTCMonth();
19719 // Common date-resetting loop -- if date is beyond end of month, make it
19722 new_date.setUTCDate(--day);
19723 new_date.setUTCMonth(new_month);
19728 moveYear: function(date, dir)
19730 return this.moveMonth(date, dir*12);
19733 dateWithinRange: function(date)
19735 return date >= this.startDate && date <= this.endDate;
19741 this.picker().remove();
19744 validateValue : function(value)
19746 if(this.getVisibilityEl().hasClass('hidden')){
19750 if(value.length < 1) {
19751 if(this.allowBlank){
19757 if(value.length < this.minLength){
19760 if(value.length > this.maxLength){
19764 var vt = Roo.form.VTypes;
19765 if(!vt[this.vtype](value, this)){
19769 if(typeof this.validator == "function"){
19770 var msg = this.validator(value);
19776 if(this.regex && !this.regex.test(value)){
19780 if(typeof(this.parseDate(value)) == 'undefined'){
19784 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19788 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19798 this.date = this.viewDate = '';
19800 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19805 Roo.apply(Roo.bootstrap.DateField, {
19816 html: '<i class="fa fa-arrow-left"/>'
19826 html: '<i class="fa fa-arrow-right"/>'
19868 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19869 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19870 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19871 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19872 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19885 navFnc: 'FullYear',
19890 navFnc: 'FullYear',
19895 Roo.apply(Roo.bootstrap.DateField, {
19899 cls: 'datepicker dropdown-menu roo-dynamic',
19903 cls: 'datepicker-days',
19907 cls: 'table-condensed',
19909 Roo.bootstrap.DateField.head,
19913 Roo.bootstrap.DateField.footer
19920 cls: 'datepicker-months',
19924 cls: 'table-condensed',
19926 Roo.bootstrap.DateField.head,
19927 Roo.bootstrap.DateField.content,
19928 Roo.bootstrap.DateField.footer
19935 cls: 'datepicker-years',
19939 cls: 'table-condensed',
19941 Roo.bootstrap.DateField.head,
19942 Roo.bootstrap.DateField.content,
19943 Roo.bootstrap.DateField.footer
19962 * @class Roo.bootstrap.TimeField
19963 * @extends Roo.bootstrap.Input
19964 * Bootstrap DateField class
19968 * Create a new TimeField
19969 * @param {Object} config The config object
19972 Roo.bootstrap.TimeField = function(config){
19973 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19977 * Fires when this field show.
19978 * @param {Roo.bootstrap.DateField} thisthis
19979 * @param {Mixed} date The date value
19984 * Fires when this field hide.
19985 * @param {Roo.bootstrap.DateField} this
19986 * @param {Mixed} date The date value
19991 * Fires when select a date.
19992 * @param {Roo.bootstrap.DateField} this
19993 * @param {Mixed} date The date value
19999 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20002 * @cfg {String} format
20003 * The default time format string which can be overriden for localization support. The format must be
20004 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20008 onRender: function(ct, position)
20011 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20013 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20015 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20017 this.pop = this.picker().select('>.datepicker-time',true).first();
20018 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20020 this.picker().on('mousedown', this.onMousedown, this);
20021 this.picker().on('click', this.onClick, this);
20023 this.picker().addClass('datepicker-dropdown');
20028 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20029 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20030 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20031 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20032 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20033 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20037 fireKey: function(e){
20038 if (!this.picker().isVisible()){
20039 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20045 e.preventDefault();
20053 this.onTogglePeriod();
20056 this.onIncrementMinutes();
20059 this.onDecrementMinutes();
20068 onClick: function(e) {
20069 e.stopPropagation();
20070 e.preventDefault();
20073 picker : function()
20075 return this.el.select('.datepicker', true).first();
20078 fillTime: function()
20080 var time = this.pop.select('tbody', true).first();
20082 time.dom.innerHTML = '';
20097 cls: 'hours-up glyphicon glyphicon-chevron-up'
20117 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20138 cls: 'timepicker-hour',
20153 cls: 'timepicker-minute',
20168 cls: 'btn btn-primary period',
20190 cls: 'hours-down glyphicon glyphicon-chevron-down'
20210 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20228 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20235 var hours = this.time.getHours();
20236 var minutes = this.time.getMinutes();
20249 hours = hours - 12;
20253 hours = '0' + hours;
20257 minutes = '0' + minutes;
20260 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20261 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20262 this.pop.select('button', true).first().dom.innerHTML = period;
20268 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20270 var cls = ['bottom'];
20272 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20279 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20284 this.picker().addClass(cls.join('-'));
20288 Roo.each(cls, function(c){
20290 _this.picker().setTop(_this.inputEl().getHeight());
20294 _this.picker().setTop(0 - _this.picker().getHeight());
20299 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20303 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20310 onFocus : function()
20312 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20316 onBlur : function()
20318 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20324 this.picker().show();
20329 this.fireEvent('show', this, this.date);
20334 this.picker().hide();
20337 this.fireEvent('hide', this, this.date);
20340 setTime : function()
20343 this.setValue(this.time.format(this.format));
20345 this.fireEvent('select', this, this.date);
20350 onMousedown: function(e){
20351 e.stopPropagation();
20352 e.preventDefault();
20355 onIncrementHours: function()
20357 Roo.log('onIncrementHours');
20358 this.time = this.time.add(Date.HOUR, 1);
20363 onDecrementHours: function()
20365 Roo.log('onDecrementHours');
20366 this.time = this.time.add(Date.HOUR, -1);
20370 onIncrementMinutes: function()
20372 Roo.log('onIncrementMinutes');
20373 this.time = this.time.add(Date.MINUTE, 1);
20377 onDecrementMinutes: function()
20379 Roo.log('onDecrementMinutes');
20380 this.time = this.time.add(Date.MINUTE, -1);
20384 onTogglePeriod: function()
20386 Roo.log('onTogglePeriod');
20387 this.time = this.time.add(Date.HOUR, 12);
20394 Roo.apply(Roo.bootstrap.TimeField, {
20424 cls: 'btn btn-info ok',
20436 Roo.apply(Roo.bootstrap.TimeField, {
20440 cls: 'datepicker dropdown-menu',
20444 cls: 'datepicker-time',
20448 cls: 'table-condensed',
20450 Roo.bootstrap.TimeField.content,
20451 Roo.bootstrap.TimeField.footer
20470 * @class Roo.bootstrap.MonthField
20471 * @extends Roo.bootstrap.Input
20472 * Bootstrap MonthField class
20474 * @cfg {String} language default en
20477 * Create a new MonthField
20478 * @param {Object} config The config object
20481 Roo.bootstrap.MonthField = function(config){
20482 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20487 * Fires when this field show.
20488 * @param {Roo.bootstrap.MonthField} this
20489 * @param {Mixed} date The date value
20494 * Fires when this field hide.
20495 * @param {Roo.bootstrap.MonthField} this
20496 * @param {Mixed} date The date value
20501 * Fires when select a date.
20502 * @param {Roo.bootstrap.MonthField} this
20503 * @param {String} oldvalue The old value
20504 * @param {String} newvalue The new value
20510 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20512 onRender: function(ct, position)
20515 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20517 this.language = this.language || 'en';
20518 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20519 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20521 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20522 this.isInline = false;
20523 this.isInput = true;
20524 this.component = this.el.select('.add-on', true).first() || false;
20525 this.component = (this.component && this.component.length === 0) ? false : this.component;
20526 this.hasInput = this.component && this.inputEL().length;
20528 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20530 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20532 this.picker().on('mousedown', this.onMousedown, this);
20533 this.picker().on('click', this.onClick, this);
20535 this.picker().addClass('datepicker-dropdown');
20537 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20538 v.setStyle('width', '189px');
20545 if(this.isInline) {
20551 setValue: function(v, suppressEvent)
20553 var o = this.getValue();
20555 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20559 if(suppressEvent !== true){
20560 this.fireEvent('select', this, o, v);
20565 getValue: function()
20570 onClick: function(e)
20572 e.stopPropagation();
20573 e.preventDefault();
20575 var target = e.getTarget();
20577 if(target.nodeName.toLowerCase() === 'i'){
20578 target = Roo.get(target).dom.parentNode;
20581 var nodeName = target.nodeName;
20582 var className = target.className;
20583 var html = target.innerHTML;
20585 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20589 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20591 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20597 picker : function()
20599 return this.pickerEl;
20602 fillMonths: function()
20605 var months = this.picker().select('>.datepicker-months td', true).first();
20607 months.dom.innerHTML = '';
20613 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20616 months.createChild(month);
20625 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20626 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20629 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20630 e.removeClass('active');
20632 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20633 e.addClass('active');
20640 if(this.isInline) {
20644 this.picker().removeClass(['bottom', 'top']);
20646 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20648 * place to the top of element!
20652 this.picker().addClass('top');
20653 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20658 this.picker().addClass('bottom');
20660 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20663 onFocus : function()
20665 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20669 onBlur : function()
20671 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20673 var d = this.inputEl().getValue();
20682 this.picker().show();
20683 this.picker().select('>.datepicker-months', true).first().show();
20687 this.fireEvent('show', this, this.date);
20692 if(this.isInline) {
20695 this.picker().hide();
20696 this.fireEvent('hide', this, this.date);
20700 onMousedown: function(e)
20702 e.stopPropagation();
20703 e.preventDefault();
20708 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20712 fireKey: function(e)
20714 if (!this.picker().isVisible()){
20715 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20726 e.preventDefault();
20730 dir = e.keyCode == 37 ? -1 : 1;
20732 this.vIndex = this.vIndex + dir;
20734 if(this.vIndex < 0){
20738 if(this.vIndex > 11){
20742 if(isNaN(this.vIndex)){
20746 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20752 dir = e.keyCode == 38 ? -1 : 1;
20754 this.vIndex = this.vIndex + dir * 4;
20756 if(this.vIndex < 0){
20760 if(this.vIndex > 11){
20764 if(isNaN(this.vIndex)){
20768 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20773 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20774 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20778 e.preventDefault();
20781 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20782 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20798 this.picker().remove();
20803 Roo.apply(Roo.bootstrap.MonthField, {
20822 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20823 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20828 Roo.apply(Roo.bootstrap.MonthField, {
20832 cls: 'datepicker dropdown-menu roo-dynamic',
20836 cls: 'datepicker-months',
20840 cls: 'table-condensed',
20842 Roo.bootstrap.DateField.content
20862 * @class Roo.bootstrap.CheckBox
20863 * @extends Roo.bootstrap.Input
20864 * Bootstrap CheckBox class
20866 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20867 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20868 * @cfg {String} boxLabel The text that appears beside the checkbox
20869 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20870 * @cfg {Boolean} checked initnal the element
20871 * @cfg {Boolean} inline inline the element (default false)
20872 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20873 * @cfg {String} tooltip label tooltip
20876 * Create a new CheckBox
20877 * @param {Object} config The config object
20880 Roo.bootstrap.CheckBox = function(config){
20881 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20886 * Fires when the element is checked or unchecked.
20887 * @param {Roo.bootstrap.CheckBox} this This input
20888 * @param {Boolean} checked The new checked value
20893 * Fires when the element is click.
20894 * @param {Roo.bootstrap.CheckBox} this This input
20901 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20903 inputType: 'checkbox',
20912 // checkbox success does not make any sense really..
20917 getAutoCreate : function()
20919 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20925 cfg.cls = 'form-group ' + this.inputType; //input-group
20928 cfg.cls += ' ' + this.inputType + '-inline';
20934 type : this.inputType,
20935 value : this.inputValue,
20936 cls : 'roo-' + this.inputType, //'form-box',
20937 placeholder : this.placeholder || ''
20941 if(this.inputType != 'radio'){
20945 cls : 'roo-hidden-value',
20946 value : this.checked ? this.inputValue : this.valueOff
20951 if (this.weight) { // Validity check?
20952 cfg.cls += " " + this.inputType + "-" + this.weight;
20955 if (this.disabled) {
20956 input.disabled=true;
20960 input.checked = this.checked;
20965 input.name = this.name;
20967 if(this.inputType != 'radio'){
20968 hidden.name = this.name;
20969 input.name = '_hidden_' + this.name;
20974 input.cls += ' input-' + this.size;
20979 ['xs','sm','md','lg'].map(function(size){
20980 if (settings[size]) {
20981 cfg.cls += ' col-' + size + '-' + settings[size];
20985 var inputblock = input;
20987 if (this.before || this.after) {
20990 cls : 'input-group',
20995 inputblock.cn.push({
20997 cls : 'input-group-addon',
21002 inputblock.cn.push(input);
21004 if(this.inputType != 'radio'){
21005 inputblock.cn.push(hidden);
21009 inputblock.cn.push({
21011 cls : 'input-group-addon',
21017 var boxLabelCfg = false;
21023 //'for': id, // box label is handled by onclick - so no for...
21025 html: this.boxLabel
21028 boxLabelCfg.tooltip = this.tooltip;
21034 if (align ==='left' && this.fieldLabel.length) {
21035 // Roo.log("left and has label");
21040 cls : 'control-label',
21041 html : this.fieldLabel
21052 cfg.cn[1].cn.push(boxLabelCfg);
21055 if(this.labelWidth > 12){
21056 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21059 if(this.labelWidth < 13 && this.labelmd == 0){
21060 this.labelmd = this.labelWidth;
21063 if(this.labellg > 0){
21064 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21065 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21068 if(this.labelmd > 0){
21069 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21070 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21073 if(this.labelsm > 0){
21074 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21075 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21078 if(this.labelxs > 0){
21079 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21080 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21083 } else if ( this.fieldLabel.length) {
21084 // Roo.log(" label");
21088 tag: this.boxLabel ? 'span' : 'label',
21090 cls: 'control-label box-input-label',
21091 //cls : 'input-group-addon',
21092 html : this.fieldLabel
21099 cfg.cn.push(boxLabelCfg);
21104 // Roo.log(" no label && no align");
21105 cfg.cn = [ inputblock ] ;
21107 cfg.cn.push(boxLabelCfg);
21115 if(this.inputType != 'radio'){
21116 cfg.cn.push(hidden);
21124 * return the real input element.
21126 inputEl: function ()
21128 return this.el.select('input.roo-' + this.inputType,true).first();
21130 hiddenEl: function ()
21132 return this.el.select('input.roo-hidden-value',true).first();
21135 labelEl: function()
21137 return this.el.select('label.control-label',true).first();
21139 /* depricated... */
21143 return this.labelEl();
21146 boxLabelEl: function()
21148 return this.el.select('label.box-label',true).first();
21151 initEvents : function()
21153 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21155 this.inputEl().on('click', this.onClick, this);
21157 if (this.boxLabel) {
21158 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21161 this.startValue = this.getValue();
21164 Roo.bootstrap.CheckBox.register(this);
21168 onClick : function(e)
21170 if(this.fireEvent('click', this, e) !== false){
21171 this.setChecked(!this.checked);
21176 setChecked : function(state,suppressEvent)
21178 this.startValue = this.getValue();
21180 if(this.inputType == 'radio'){
21182 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21183 e.dom.checked = false;
21186 this.inputEl().dom.checked = true;
21188 this.inputEl().dom.value = this.inputValue;
21190 if(suppressEvent !== true){
21191 this.fireEvent('check', this, true);
21199 this.checked = state;
21201 this.inputEl().dom.checked = state;
21204 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21206 if(suppressEvent !== true){
21207 this.fireEvent('check', this, state);
21213 getValue : function()
21215 if(this.inputType == 'radio'){
21216 return this.getGroupValue();
21219 return this.hiddenEl().dom.value;
21223 getGroupValue : function()
21225 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21229 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21232 setValue : function(v,suppressEvent)
21234 if(this.inputType == 'radio'){
21235 this.setGroupValue(v, suppressEvent);
21239 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21244 setGroupValue : function(v, suppressEvent)
21246 this.startValue = this.getValue();
21248 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21249 e.dom.checked = false;
21251 if(e.dom.value == v){
21252 e.dom.checked = true;
21256 if(suppressEvent !== true){
21257 this.fireEvent('check', this, true);
21265 validate : function()
21267 if(this.getVisibilityEl().hasClass('hidden')){
21273 (this.inputType == 'radio' && this.validateRadio()) ||
21274 (this.inputType == 'checkbox' && this.validateCheckbox())
21280 this.markInvalid();
21284 validateRadio : function()
21286 if(this.getVisibilityEl().hasClass('hidden')){
21290 if(this.allowBlank){
21296 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21297 if(!e.dom.checked){
21309 validateCheckbox : function()
21312 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21313 //return (this.getValue() == this.inputValue) ? true : false;
21316 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21324 for(var i in group){
21325 if(group[i].el.isVisible(true)){
21333 for(var i in group){
21338 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21345 * Mark this field as valid
21347 markValid : function()
21351 this.fireEvent('valid', this);
21353 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21356 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21363 if(this.inputType == 'radio'){
21364 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21365 var fg = e.findParent('.form-group', false, true);
21366 if (Roo.bootstrap.version == 3) {
21367 fg.removeClass([_this.invalidClass, _this.validClass]);
21368 fg.addClass(_this.validClass);
21370 fg.removeClass(['is-valid', 'is-invalid']);
21371 fg.addClass('is-valid');
21379 var fg = this.el.findParent('.form-group', false, true);
21380 if (Roo.bootstrap.version == 3) {
21381 fg.removeClass([this.invalidClass, this.validClass]);
21382 fg.addClass(this.validClass);
21384 fg.removeClass(['is-valid', 'is-invalid']);
21385 fg.addClass('is-valid');
21390 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21396 for(var i in group){
21397 var fg = group[i].el.findParent('.form-group', false, true);
21398 if (Roo.bootstrap.version == 3) {
21399 fg.removeClass([this.invalidClass, this.validClass]);
21400 fg.addClass(this.validClass);
21402 fg.removeClass(['is-valid', 'is-invalid']);
21403 fg.addClass('is-valid');
21409 * Mark this field as invalid
21410 * @param {String} msg The validation message
21412 markInvalid : function(msg)
21414 if(this.allowBlank){
21420 this.fireEvent('invalid', this, msg);
21422 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21425 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21429 label.markInvalid();
21432 if(this.inputType == 'radio'){
21434 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21435 var fg = e.findParent('.form-group', false, true);
21436 if (Roo.bootstrap.version == 3) {
21437 fg.removeClass([_this.invalidClass, _this.validClass]);
21438 fg.addClass(_this.invalidClass);
21440 fg.removeClass(['is-invalid', 'is-valid']);
21441 fg.addClass('is-invalid');
21449 var fg = this.el.findParent('.form-group', false, true);
21450 if (Roo.bootstrap.version == 3) {
21451 fg.removeClass([_this.invalidClass, _this.validClass]);
21452 fg.addClass(_this.invalidClass);
21454 fg.removeClass(['is-invalid', 'is-valid']);
21455 fg.addClass('is-invalid');
21460 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21466 for(var i in group){
21467 var fg = group[i].el.findParent('.form-group', false, true);
21468 if (Roo.bootstrap.version == 3) {
21469 fg.removeClass([_this.invalidClass, _this.validClass]);
21470 fg.addClass(_this.invalidClass);
21472 fg.removeClass(['is-invalid', 'is-valid']);
21473 fg.addClass('is-invalid');
21479 clearInvalid : function()
21481 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21483 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21485 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21487 if (label && label.iconEl) {
21488 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21489 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21493 disable : function()
21495 if(this.inputType != 'radio'){
21496 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21503 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21504 _this.getActionEl().addClass(this.disabledClass);
21505 e.dom.disabled = true;
21509 this.disabled = true;
21510 this.fireEvent("disable", this);
21514 enable : function()
21516 if(this.inputType != 'radio'){
21517 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21524 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21525 _this.getActionEl().removeClass(this.disabledClass);
21526 e.dom.disabled = false;
21530 this.disabled = false;
21531 this.fireEvent("enable", this);
21535 setBoxLabel : function(v)
21540 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21546 Roo.apply(Roo.bootstrap.CheckBox, {
21551 * register a CheckBox Group
21552 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21554 register : function(checkbox)
21556 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21557 this.groups[checkbox.groupId] = {};
21560 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21564 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21568 * fetch a CheckBox Group based on the group ID
21569 * @param {string} the group ID
21570 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21572 get: function(groupId) {
21573 if (typeof(this.groups[groupId]) == 'undefined') {
21577 return this.groups[groupId] ;
21590 * @class Roo.bootstrap.Radio
21591 * @extends Roo.bootstrap.Component
21592 * Bootstrap Radio class
21593 * @cfg {String} boxLabel - the label associated
21594 * @cfg {String} value - the value of radio
21597 * Create a new Radio
21598 * @param {Object} config The config object
21600 Roo.bootstrap.Radio = function(config){
21601 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21605 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21611 getAutoCreate : function()
21615 cls : 'form-group radio',
21620 html : this.boxLabel
21628 initEvents : function()
21630 this.parent().register(this);
21632 this.el.on('click', this.onClick, this);
21636 onClick : function(e)
21638 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21639 this.setChecked(true);
21643 setChecked : function(state, suppressEvent)
21645 this.parent().setValue(this.value, suppressEvent);
21649 setBoxLabel : function(v)
21654 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21669 * @class Roo.bootstrap.SecurePass
21670 * @extends Roo.bootstrap.Input
21671 * Bootstrap SecurePass class
21675 * Create a new SecurePass
21676 * @param {Object} config The config object
21679 Roo.bootstrap.SecurePass = function (config) {
21680 // these go here, so the translation tool can replace them..
21682 PwdEmpty: "Please type a password, and then retype it to confirm.",
21683 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21684 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21685 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21686 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21687 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21688 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21689 TooWeak: "Your password is Too Weak."
21691 this.meterLabel = "Password strength:";
21692 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21693 this.meterClass = [
21694 "roo-password-meter-tooweak",
21695 "roo-password-meter-weak",
21696 "roo-password-meter-medium",
21697 "roo-password-meter-strong",
21698 "roo-password-meter-grey"
21703 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21706 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21708 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21710 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21711 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21712 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21713 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21714 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21715 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21716 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21726 * @cfg {String/Object} Label for the strength meter (defaults to
21727 * 'Password strength:')
21732 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21733 * ['Weak', 'Medium', 'Strong'])
21736 pwdStrengths: false,
21749 initEvents: function ()
21751 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21753 if (this.el.is('input[type=password]') && Roo.isSafari) {
21754 this.el.on('keydown', this.SafariOnKeyDown, this);
21757 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21760 onRender: function (ct, position)
21762 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21763 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21764 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21766 this.trigger.createChild({
21771 cls: 'roo-password-meter-grey col-xs-12',
21774 //width: this.meterWidth + 'px'
21778 cls: 'roo-password-meter-text'
21784 if (this.hideTrigger) {
21785 this.trigger.setDisplayed(false);
21787 this.setSize(this.width || '', this.height || '');
21790 onDestroy: function ()
21792 if (this.trigger) {
21793 this.trigger.removeAllListeners();
21794 this.trigger.remove();
21797 this.wrap.remove();
21799 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21802 checkStrength: function ()
21804 var pwd = this.inputEl().getValue();
21805 if (pwd == this._lastPwd) {
21810 if (this.ClientSideStrongPassword(pwd)) {
21812 } else if (this.ClientSideMediumPassword(pwd)) {
21814 } else if (this.ClientSideWeakPassword(pwd)) {
21820 Roo.log('strength1: ' + strength);
21822 //var pm = this.trigger.child('div/div/div').dom;
21823 var pm = this.trigger.child('div/div');
21824 pm.removeClass(this.meterClass);
21825 pm.addClass(this.meterClass[strength]);
21828 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21830 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21832 this._lastPwd = pwd;
21836 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21838 this._lastPwd = '';
21840 var pm = this.trigger.child('div/div');
21841 pm.removeClass(this.meterClass);
21842 pm.addClass('roo-password-meter-grey');
21845 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21848 this.inputEl().dom.type='password';
21851 validateValue: function (value)
21854 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21857 if (value.length == 0) {
21858 if (this.allowBlank) {
21859 this.clearInvalid();
21863 this.markInvalid(this.errors.PwdEmpty);
21864 this.errorMsg = this.errors.PwdEmpty;
21872 if ('[\x21-\x7e]*'.match(value)) {
21873 this.markInvalid(this.errors.PwdBadChar);
21874 this.errorMsg = this.errors.PwdBadChar;
21877 if (value.length < 6) {
21878 this.markInvalid(this.errors.PwdShort);
21879 this.errorMsg = this.errors.PwdShort;
21882 if (value.length > 16) {
21883 this.markInvalid(this.errors.PwdLong);
21884 this.errorMsg = this.errors.PwdLong;
21888 if (this.ClientSideStrongPassword(value)) {
21890 } else if (this.ClientSideMediumPassword(value)) {
21892 } else if (this.ClientSideWeakPassword(value)) {
21899 if (strength < 2) {
21900 //this.markInvalid(this.errors.TooWeak);
21901 this.errorMsg = this.errors.TooWeak;
21906 console.log('strength2: ' + strength);
21908 //var pm = this.trigger.child('div/div/div').dom;
21910 var pm = this.trigger.child('div/div');
21911 pm.removeClass(this.meterClass);
21912 pm.addClass(this.meterClass[strength]);
21914 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21916 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21918 this.errorMsg = '';
21922 CharacterSetChecks: function (type)
21925 this.fResult = false;
21928 isctype: function (character, type)
21931 case this.kCapitalLetter:
21932 if (character >= 'A' && character <= 'Z') {
21937 case this.kSmallLetter:
21938 if (character >= 'a' && character <= 'z') {
21944 if (character >= '0' && character <= '9') {
21949 case this.kPunctuation:
21950 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21961 IsLongEnough: function (pwd, size)
21963 return !(pwd == null || isNaN(size) || pwd.length < size);
21966 SpansEnoughCharacterSets: function (word, nb)
21968 if (!this.IsLongEnough(word, nb))
21973 var characterSetChecks = new Array(
21974 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21975 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21978 for (var index = 0; index < word.length; ++index) {
21979 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21980 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21981 characterSetChecks[nCharSet].fResult = true;
21988 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21989 if (characterSetChecks[nCharSet].fResult) {
21994 if (nCharSets < nb) {
22000 ClientSideStrongPassword: function (pwd)
22002 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
22005 ClientSideMediumPassword: function (pwd)
22007 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22010 ClientSideWeakPassword: function (pwd)
22012 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22015 })//<script type="text/javascript">
22018 * Based Ext JS Library 1.1.1
22019 * Copyright(c) 2006-2007, Ext JS, LLC.
22025 * @class Roo.HtmlEditorCore
22026 * @extends Roo.Component
22027 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22029 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22032 Roo.HtmlEditorCore = function(config){
22035 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22040 * @event initialize
22041 * Fires when the editor is fully initialized (including the iframe)
22042 * @param {Roo.HtmlEditorCore} this
22047 * Fires when the editor is first receives the focus. Any insertion must wait
22048 * until after this event.
22049 * @param {Roo.HtmlEditorCore} this
22053 * @event beforesync
22054 * Fires before the textarea is updated with content from the editor iframe. Return false
22055 * to cancel the sync.
22056 * @param {Roo.HtmlEditorCore} this
22057 * @param {String} html
22061 * @event beforepush
22062 * Fires before the iframe editor is updated with content from the textarea. Return false
22063 * to cancel the push.
22064 * @param {Roo.HtmlEditorCore} this
22065 * @param {String} html
22070 * Fires when the textarea is updated with content from the editor iframe.
22071 * @param {Roo.HtmlEditorCore} this
22072 * @param {String} html
22077 * Fires when the iframe editor is updated with content from the textarea.
22078 * @param {Roo.HtmlEditorCore} this
22079 * @param {String} html
22084 * @event editorevent
22085 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22086 * @param {Roo.HtmlEditorCore} this
22092 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22094 // defaults : white / black...
22095 this.applyBlacklists();
22102 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22106 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22112 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22117 * @cfg {Number} height (in pixels)
22121 * @cfg {Number} width (in pixels)
22126 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22129 stylesheets: false,
22134 // private properties
22135 validationEvent : false,
22137 initialized : false,
22139 sourceEditMode : false,
22140 onFocus : Roo.emptyFn,
22142 hideMode:'offsets',
22146 // blacklist + whitelisted elements..
22153 * Protected method that will not generally be called directly. It
22154 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22155 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22157 getDocMarkup : function(){
22161 // inherit styels from page...??
22162 if (this.stylesheets === false) {
22164 Roo.get(document.head).select('style').each(function(node) {
22165 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22168 Roo.get(document.head).select('link').each(function(node) {
22169 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22172 } else if (!this.stylesheets.length) {
22174 st = '<style type="text/css">' +
22175 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22178 st = '<style type="text/css">' +
22183 st += '<style type="text/css">' +
22184 'IMG { cursor: pointer } ' +
22187 var cls = 'roo-htmleditor-body';
22189 if(this.bodyCls.length){
22190 cls += ' ' + this.bodyCls;
22193 return '<html><head>' + st +
22194 //<style type="text/css">' +
22195 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22197 ' </head><body class="' + cls + '"></body></html>';
22201 onRender : function(ct, position)
22204 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22205 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22208 this.el.dom.style.border = '0 none';
22209 this.el.dom.setAttribute('tabIndex', -1);
22210 this.el.addClass('x-hidden hide');
22214 if(Roo.isIE){ // fix IE 1px bogus margin
22215 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22219 this.frameId = Roo.id();
22223 var iframe = this.owner.wrap.createChild({
22225 cls: 'form-control', // bootstrap..
22227 name: this.frameId,
22228 frameBorder : 'no',
22229 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22234 this.iframe = iframe.dom;
22236 this.assignDocWin();
22238 this.doc.designMode = 'on';
22241 this.doc.write(this.getDocMarkup());
22245 var task = { // must defer to wait for browser to be ready
22247 //console.log("run task?" + this.doc.readyState);
22248 this.assignDocWin();
22249 if(this.doc.body || this.doc.readyState == 'complete'){
22251 this.doc.designMode="on";
22255 Roo.TaskMgr.stop(task);
22256 this.initEditor.defer(10, this);
22263 Roo.TaskMgr.start(task);
22268 onResize : function(w, h)
22270 Roo.log('resize: ' +w + ',' + h );
22271 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22275 if(typeof w == 'number'){
22277 this.iframe.style.width = w + 'px';
22279 if(typeof h == 'number'){
22281 this.iframe.style.height = h + 'px';
22283 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22290 * Toggles the editor between standard and source edit mode.
22291 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22293 toggleSourceEdit : function(sourceEditMode){
22295 this.sourceEditMode = sourceEditMode === true;
22297 if(this.sourceEditMode){
22299 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22302 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22303 //this.iframe.className = '';
22306 //this.setSize(this.owner.wrap.getSize());
22307 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22314 * Protected method that will not generally be called directly. If you need/want
22315 * custom HTML cleanup, this is the method you should override.
22316 * @param {String} html The HTML to be cleaned
22317 * return {String} The cleaned HTML
22319 cleanHtml : function(html){
22320 html = String(html);
22321 if(html.length > 5){
22322 if(Roo.isSafari){ // strip safari nonsense
22323 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22326 if(html == ' '){
22333 * HTML Editor -> Textarea
22334 * Protected method that will not generally be called directly. Syncs the contents
22335 * of the editor iframe with the textarea.
22337 syncValue : function(){
22338 if(this.initialized){
22339 var bd = (this.doc.body || this.doc.documentElement);
22340 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22341 var html = bd.innerHTML;
22343 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22344 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22346 html = '<div style="'+m[0]+'">' + html + '</div>';
22349 html = this.cleanHtml(html);
22350 // fix up the special chars.. normaly like back quotes in word...
22351 // however we do not want to do this with chinese..
22352 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
22354 var cc = match.charCodeAt();
22356 // Get the character value, handling surrogate pairs
22357 if (match.length == 2) {
22358 // It's a surrogate pair, calculate the Unicode code point
22359 var high = match.charCodeAt(0) - 0xD800;
22360 var low = match.charCodeAt(1) - 0xDC00;
22361 cc = (high * 0x400) + low + 0x10000;
22363 (cc >= 0x4E00 && cc < 0xA000 ) ||
22364 (cc >= 0x3400 && cc < 0x4E00 ) ||
22365 (cc >= 0xf900 && cc < 0xfb00 )
22370 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
22371 return "&#" + cc + ";";
22378 if(this.owner.fireEvent('beforesync', this, html) !== false){
22379 this.el.dom.value = html;
22380 this.owner.fireEvent('sync', this, html);
22386 * Protected method that will not generally be called directly. Pushes the value of the textarea
22387 * into the iframe editor.
22389 pushValue : function(){
22390 if(this.initialized){
22391 var v = this.el.dom.value.trim();
22393 // if(v.length < 1){
22397 if(this.owner.fireEvent('beforepush', this, v) !== false){
22398 var d = (this.doc.body || this.doc.documentElement);
22400 this.cleanUpPaste();
22401 this.el.dom.value = d.innerHTML;
22402 this.owner.fireEvent('push', this, v);
22408 deferFocus : function(){
22409 this.focus.defer(10, this);
22413 focus : function(){
22414 if(this.win && !this.sourceEditMode){
22421 assignDocWin: function()
22423 var iframe = this.iframe;
22426 this.doc = iframe.contentWindow.document;
22427 this.win = iframe.contentWindow;
22429 // if (!Roo.get(this.frameId)) {
22432 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22433 // this.win = Roo.get(this.frameId).dom.contentWindow;
22435 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22439 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22440 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22445 initEditor : function(){
22446 //console.log("INIT EDITOR");
22447 this.assignDocWin();
22451 this.doc.designMode="on";
22453 this.doc.write(this.getDocMarkup());
22456 var dbody = (this.doc.body || this.doc.documentElement);
22457 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22458 // this copies styles from the containing element into thsi one..
22459 // not sure why we need all of this..
22460 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22462 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22463 //ss['background-attachment'] = 'fixed'; // w3c
22464 dbody.bgProperties = 'fixed'; // ie
22465 //Roo.DomHelper.applyStyles(dbody, ss);
22466 Roo.EventManager.on(this.doc, {
22467 //'mousedown': this.onEditorEvent,
22468 'mouseup': this.onEditorEvent,
22469 'dblclick': this.onEditorEvent,
22470 'click': this.onEditorEvent,
22471 'keyup': this.onEditorEvent,
22476 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22478 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22479 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22481 this.initialized = true;
22483 this.owner.fireEvent('initialize', this);
22488 onDestroy : function(){
22494 //for (var i =0; i < this.toolbars.length;i++) {
22495 // // fixme - ask toolbars for heights?
22496 // this.toolbars[i].onDestroy();
22499 //this.wrap.dom.innerHTML = '';
22500 //this.wrap.remove();
22505 onFirstFocus : function(){
22507 this.assignDocWin();
22510 this.activated = true;
22513 if(Roo.isGecko){ // prevent silly gecko errors
22515 var s = this.win.getSelection();
22516 if(!s.focusNode || s.focusNode.nodeType != 3){
22517 var r = s.getRangeAt(0);
22518 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22523 this.execCmd('useCSS', true);
22524 this.execCmd('styleWithCSS', false);
22527 this.owner.fireEvent('activate', this);
22531 adjustFont: function(btn){
22532 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22533 //if(Roo.isSafari){ // safari
22536 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22537 if(Roo.isSafari){ // safari
22538 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22539 v = (v < 10) ? 10 : v;
22540 v = (v > 48) ? 48 : v;
22541 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22546 v = Math.max(1, v+adjust);
22548 this.execCmd('FontSize', v );
22551 onEditorEvent : function(e)
22553 this.owner.fireEvent('editorevent', this, e);
22554 // this.updateToolbar();
22555 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22558 insertTag : function(tg)
22560 // could be a bit smarter... -> wrap the current selected tRoo..
22561 if (tg.toLowerCase() == 'span' ||
22562 tg.toLowerCase() == 'code' ||
22563 tg.toLowerCase() == 'sup' ||
22564 tg.toLowerCase() == 'sub'
22567 range = this.createRange(this.getSelection());
22568 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22569 wrappingNode.appendChild(range.extractContents());
22570 range.insertNode(wrappingNode);
22577 this.execCmd("formatblock", tg);
22581 insertText : function(txt)
22585 var range = this.createRange();
22586 range.deleteContents();
22587 //alert(Sender.getAttribute('label'));
22589 range.insertNode(this.doc.createTextNode(txt));
22595 * Executes a Midas editor command on the editor document and performs necessary focus and
22596 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22597 * @param {String} cmd The Midas command
22598 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22600 relayCmd : function(cmd, value){
22602 this.execCmd(cmd, value);
22603 this.owner.fireEvent('editorevent', this);
22604 //this.updateToolbar();
22605 this.owner.deferFocus();
22609 * Executes a Midas editor command directly on the editor document.
22610 * For visual commands, you should use {@link #relayCmd} instead.
22611 * <b>This should only be called after the editor is initialized.</b>
22612 * @param {String} cmd The Midas command
22613 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22615 execCmd : function(cmd, value){
22616 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22623 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22625 * @param {String} text | dom node..
22627 insertAtCursor : function(text)
22630 if(!this.activated){
22636 var r = this.doc.selection.createRange();
22647 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22651 // from jquery ui (MIT licenced)
22653 var win = this.win;
22655 if (win.getSelection && win.getSelection().getRangeAt) {
22656 range = win.getSelection().getRangeAt(0);
22657 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22658 range.insertNode(node);
22659 } else if (win.document.selection && win.document.selection.createRange) {
22660 // no firefox support
22661 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22662 win.document.selection.createRange().pasteHTML(txt);
22664 // no firefox support
22665 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22666 this.execCmd('InsertHTML', txt);
22675 mozKeyPress : function(e){
22677 var c = e.getCharCode(), cmd;
22680 c = String.fromCharCode(c).toLowerCase();
22694 this.cleanUpPaste.defer(100, this);
22702 e.preventDefault();
22710 fixKeys : function(){ // load time branching for fastest keydown performance
22712 return function(e){
22713 var k = e.getKey(), r;
22716 r = this.doc.selection.createRange();
22719 r.pasteHTML('    ');
22726 r = this.doc.selection.createRange();
22728 var target = r.parentElement();
22729 if(!target || target.tagName.toLowerCase() != 'li'){
22731 r.pasteHTML('<br />');
22737 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22738 this.cleanUpPaste.defer(100, this);
22744 }else if(Roo.isOpera){
22745 return function(e){
22746 var k = e.getKey();
22750 this.execCmd('InsertHTML','    ');
22753 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22754 this.cleanUpPaste.defer(100, this);
22759 }else if(Roo.isSafari){
22760 return function(e){
22761 var k = e.getKey();
22765 this.execCmd('InsertText','\t');
22769 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22770 this.cleanUpPaste.defer(100, this);
22778 getAllAncestors: function()
22780 var p = this.getSelectedNode();
22783 a.push(p); // push blank onto stack..
22784 p = this.getParentElement();
22788 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22792 a.push(this.doc.body);
22796 lastSelNode : false,
22799 getSelection : function()
22801 this.assignDocWin();
22802 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22805 getSelectedNode: function()
22807 // this may only work on Gecko!!!
22809 // should we cache this!!!!
22814 var range = this.createRange(this.getSelection()).cloneRange();
22817 var parent = range.parentElement();
22819 var testRange = range.duplicate();
22820 testRange.moveToElementText(parent);
22821 if (testRange.inRange(range)) {
22824 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22827 parent = parent.parentElement;
22832 // is ancestor a text element.
22833 var ac = range.commonAncestorContainer;
22834 if (ac.nodeType == 3) {
22835 ac = ac.parentNode;
22838 var ar = ac.childNodes;
22841 var other_nodes = [];
22842 var has_other_nodes = false;
22843 for (var i=0;i<ar.length;i++) {
22844 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22847 // fullly contained node.
22849 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22854 // probably selected..
22855 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22856 other_nodes.push(ar[i]);
22860 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22865 has_other_nodes = true;
22867 if (!nodes.length && other_nodes.length) {
22868 nodes= other_nodes;
22870 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22876 createRange: function(sel)
22878 // this has strange effects when using with
22879 // top toolbar - not sure if it's a great idea.
22880 //this.editor.contentWindow.focus();
22881 if (typeof sel != "undefined") {
22883 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22885 return this.doc.createRange();
22888 return this.doc.createRange();
22891 getParentElement: function()
22894 this.assignDocWin();
22895 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22897 var range = this.createRange(sel);
22900 var p = range.commonAncestorContainer;
22901 while (p.nodeType == 3) { // text node
22912 * Range intersection.. the hard stuff...
22916 * [ -- selected range --- ]
22920 * if end is before start or hits it. fail.
22921 * if start is after end or hits it fail.
22923 * if either hits (but other is outside. - then it's not
22929 // @see http://www.thismuchiknow.co.uk/?p=64.
22930 rangeIntersectsNode : function(range, node)
22932 var nodeRange = node.ownerDocument.createRange();
22934 nodeRange.selectNode(node);
22936 nodeRange.selectNodeContents(node);
22939 var rangeStartRange = range.cloneRange();
22940 rangeStartRange.collapse(true);
22942 var rangeEndRange = range.cloneRange();
22943 rangeEndRange.collapse(false);
22945 var nodeStartRange = nodeRange.cloneRange();
22946 nodeStartRange.collapse(true);
22948 var nodeEndRange = nodeRange.cloneRange();
22949 nodeEndRange.collapse(false);
22951 return rangeStartRange.compareBoundaryPoints(
22952 Range.START_TO_START, nodeEndRange) == -1 &&
22953 rangeEndRange.compareBoundaryPoints(
22954 Range.START_TO_START, nodeStartRange) == 1;
22958 rangeCompareNode : function(range, node)
22960 var nodeRange = node.ownerDocument.createRange();
22962 nodeRange.selectNode(node);
22964 nodeRange.selectNodeContents(node);
22968 range.collapse(true);
22970 nodeRange.collapse(true);
22972 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22973 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22975 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22977 var nodeIsBefore = ss == 1;
22978 var nodeIsAfter = ee == -1;
22980 if (nodeIsBefore && nodeIsAfter) {
22983 if (!nodeIsBefore && nodeIsAfter) {
22984 return 1; //right trailed.
22987 if (nodeIsBefore && !nodeIsAfter) {
22988 return 2; // left trailed.
22994 // private? - in a new class?
22995 cleanUpPaste : function()
22997 // cleans up the whole document..
22998 Roo.log('cleanuppaste');
23000 this.cleanUpChildren(this.doc.body);
23001 var clean = this.cleanWordChars(this.doc.body.innerHTML);
23002 if (clean != this.doc.body.innerHTML) {
23003 this.doc.body.innerHTML = clean;
23008 cleanWordChars : function(input) {// change the chars to hex code
23009 var he = Roo.HtmlEditorCore;
23011 var output = input;
23012 Roo.each(he.swapCodes, function(sw) {
23013 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
23015 output = output.replace(swapper, sw[1]);
23022 cleanUpChildren : function (n)
23024 if (!n.childNodes.length) {
23027 for (var i = n.childNodes.length-1; i > -1 ; i--) {
23028 this.cleanUpChild(n.childNodes[i]);
23035 cleanUpChild : function (node)
23038 //console.log(node);
23039 if (node.nodeName == "#text") {
23040 // clean up silly Windows -- stuff?
23043 if (node.nodeName == "#comment") {
23044 node.parentNode.removeChild(node);
23045 // clean up silly Windows -- stuff?
23048 var lcname = node.tagName.toLowerCase();
23049 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23050 // whitelist of tags..
23052 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23054 node.parentNode.removeChild(node);
23059 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23061 // spans with no attributes - just remove them..
23062 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
23063 remove_keep_children = true;
23066 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23067 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23069 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23070 // remove_keep_children = true;
23073 if (remove_keep_children) {
23074 this.cleanUpChildren(node);
23075 // inserts everything just before this node...
23076 while (node.childNodes.length) {
23077 var cn = node.childNodes[0];
23078 node.removeChild(cn);
23079 node.parentNode.insertBefore(cn, node);
23081 node.parentNode.removeChild(node);
23085 if (!node.attributes || !node.attributes.length) {
23090 this.cleanUpChildren(node);
23094 function cleanAttr(n,v)
23097 if (v.match(/^\./) || v.match(/^\//)) {
23100 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23103 if (v.match(/^#/)) {
23106 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23107 node.removeAttribute(n);
23111 var cwhite = this.cwhite;
23112 var cblack = this.cblack;
23114 function cleanStyle(n,v)
23116 if (v.match(/expression/)) { //XSS?? should we even bother..
23117 node.removeAttribute(n);
23121 var parts = v.split(/;/);
23124 Roo.each(parts, function(p) {
23125 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23129 var l = p.split(':').shift().replace(/\s+/g,'');
23130 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23132 if ( cwhite.length && cblack.indexOf(l) > -1) {
23133 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23134 //node.removeAttribute(n);
23138 // only allow 'c whitelisted system attributes'
23139 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23140 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23141 //node.removeAttribute(n);
23151 if (clean.length) {
23152 node.setAttribute(n, clean.join(';'));
23154 node.removeAttribute(n);
23160 for (var i = node.attributes.length-1; i > -1 ; i--) {
23161 var a = node.attributes[i];
23164 if (a.name.toLowerCase().substr(0,2)=='on') {
23165 node.removeAttribute(a.name);
23168 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23169 node.removeAttribute(a.name);
23172 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23173 cleanAttr(a.name,a.value); // fixme..
23176 if (a.name == 'style') {
23177 cleanStyle(a.name,a.value);
23180 /// clean up MS crap..
23181 // tecnically this should be a list of valid class'es..
23184 if (a.name == 'class') {
23185 if (a.value.match(/^Mso/)) {
23186 node.removeAttribute('class');
23189 if (a.value.match(/^body$/)) {
23190 node.removeAttribute('class');
23201 this.cleanUpChildren(node);
23207 * Clean up MS wordisms...
23209 cleanWord : function(node)
23212 this.cleanWord(this.doc.body);
23217 node.nodeName == 'SPAN' &&
23218 !node.hasAttributes() &&
23219 node.childNodes.length == 1 &&
23220 node.firstChild.nodeName == "#text"
23222 var textNode = node.firstChild;
23223 node.removeChild(textNode);
23224 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
23225 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
23227 node.parentNode.insertBefore(textNode, node);
23228 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
23229 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
23231 node.parentNode.removeChild(node);
23234 if (node.nodeName == "#text") {
23235 // clean up silly Windows -- stuff?
23238 if (node.nodeName == "#comment") {
23239 node.parentNode.removeChild(node);
23240 // clean up silly Windows -- stuff?
23244 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23245 node.parentNode.removeChild(node);
23248 //Roo.log(node.tagName);
23249 // remove - but keep children..
23250 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
23251 //Roo.log('-- removed');
23252 while (node.childNodes.length) {
23253 var cn = node.childNodes[0];
23254 node.removeChild(cn);
23255 node.parentNode.insertBefore(cn, node);
23256 // move node to parent - and clean it..
23257 this.cleanWord(cn);
23259 node.parentNode.removeChild(node);
23260 /// no need to iterate chidlren = it's got none..
23261 //this.iterateChildren(node, this.cleanWord);
23265 if (node.className.length) {
23267 var cn = node.className.split(/\W+/);
23269 Roo.each(cn, function(cls) {
23270 if (cls.match(/Mso[a-zA-Z]+/)) {
23275 node.className = cna.length ? cna.join(' ') : '';
23277 node.removeAttribute("class");
23281 if (node.hasAttribute("lang")) {
23282 node.removeAttribute("lang");
23285 if (node.hasAttribute("style")) {
23287 var styles = node.getAttribute("style").split(";");
23289 Roo.each(styles, function(s) {
23290 if (!s.match(/:/)) {
23293 var kv = s.split(":");
23294 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23297 // what ever is left... we allow.
23300 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23301 if (!nstyle.length) {
23302 node.removeAttribute('style');
23305 this.iterateChildren(node, this.cleanWord);
23311 * iterateChildren of a Node, calling fn each time, using this as the scole..
23312 * @param {DomNode} node node to iterate children of.
23313 * @param {Function} fn method of this class to call on each item.
23315 iterateChildren : function(node, fn)
23317 if (!node.childNodes.length) {
23320 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23321 fn.call(this, node.childNodes[i])
23327 * cleanTableWidths.
23329 * Quite often pasting from word etc.. results in tables with column and widths.
23330 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23333 cleanTableWidths : function(node)
23338 this.cleanTableWidths(this.doc.body);
23343 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23346 Roo.log(node.tagName);
23347 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23348 this.iterateChildren(node, this.cleanTableWidths);
23351 if (node.hasAttribute('width')) {
23352 node.removeAttribute('width');
23356 if (node.hasAttribute("style")) {
23359 var styles = node.getAttribute("style").split(";");
23361 Roo.each(styles, function(s) {
23362 if (!s.match(/:/)) {
23365 var kv = s.split(":");
23366 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23369 // what ever is left... we allow.
23372 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23373 if (!nstyle.length) {
23374 node.removeAttribute('style');
23378 this.iterateChildren(node, this.cleanTableWidths);
23386 domToHTML : function(currentElement, depth, nopadtext) {
23388 depth = depth || 0;
23389 nopadtext = nopadtext || false;
23391 if (!currentElement) {
23392 return this.domToHTML(this.doc.body);
23395 //Roo.log(currentElement);
23397 var allText = false;
23398 var nodeName = currentElement.nodeName;
23399 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23401 if (nodeName == '#text') {
23403 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23408 if (nodeName != 'BODY') {
23411 // Prints the node tagName, such as <A>, <IMG>, etc
23414 for(i = 0; i < currentElement.attributes.length;i++) {
23416 var aname = currentElement.attributes.item(i).name;
23417 if (!currentElement.attributes.item(i).value.length) {
23420 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23423 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23432 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23435 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23440 // Traverse the tree
23442 var currentElementChild = currentElement.childNodes.item(i);
23443 var allText = true;
23444 var innerHTML = '';
23446 while (currentElementChild) {
23447 // Formatting code (indent the tree so it looks nice on the screen)
23448 var nopad = nopadtext;
23449 if (lastnode == 'SPAN') {
23453 if (currentElementChild.nodeName == '#text') {
23454 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23455 toadd = nopadtext ? toadd : toadd.trim();
23456 if (!nopad && toadd.length > 80) {
23457 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23459 innerHTML += toadd;
23462 currentElementChild = currentElement.childNodes.item(i);
23468 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23470 // Recursively traverse the tree structure of the child node
23471 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23472 lastnode = currentElementChild.nodeName;
23474 currentElementChild=currentElement.childNodes.item(i);
23480 // The remaining code is mostly for formatting the tree
23481 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23486 ret+= "</"+tagName+">";
23492 applyBlacklists : function()
23494 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23495 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23499 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23500 if (b.indexOf(tag) > -1) {
23503 this.white.push(tag);
23507 Roo.each(w, function(tag) {
23508 if (b.indexOf(tag) > -1) {
23511 if (this.white.indexOf(tag) > -1) {
23514 this.white.push(tag);
23519 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23520 if (w.indexOf(tag) > -1) {
23523 this.black.push(tag);
23527 Roo.each(b, function(tag) {
23528 if (w.indexOf(tag) > -1) {
23531 if (this.black.indexOf(tag) > -1) {
23534 this.black.push(tag);
23539 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23540 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23544 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23545 if (b.indexOf(tag) > -1) {
23548 this.cwhite.push(tag);
23552 Roo.each(w, function(tag) {
23553 if (b.indexOf(tag) > -1) {
23556 if (this.cwhite.indexOf(tag) > -1) {
23559 this.cwhite.push(tag);
23564 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23565 if (w.indexOf(tag) > -1) {
23568 this.cblack.push(tag);
23572 Roo.each(b, function(tag) {
23573 if (w.indexOf(tag) > -1) {
23576 if (this.cblack.indexOf(tag) > -1) {
23579 this.cblack.push(tag);
23584 setStylesheets : function(stylesheets)
23586 if(typeof(stylesheets) == 'string'){
23587 Roo.get(this.iframe.contentDocument.head).createChild({
23589 rel : 'stylesheet',
23598 Roo.each(stylesheets, function(s) {
23603 Roo.get(_this.iframe.contentDocument.head).createChild({
23605 rel : 'stylesheet',
23614 removeStylesheets : function()
23618 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23623 setStyle : function(style)
23625 Roo.get(this.iframe.contentDocument.head).createChild({
23634 // hide stuff that is not compatible
23648 * @event specialkey
23652 * @cfg {String} fieldClass @hide
23655 * @cfg {String} focusClass @hide
23658 * @cfg {String} autoCreate @hide
23661 * @cfg {String} inputType @hide
23664 * @cfg {String} invalidClass @hide
23667 * @cfg {String} invalidText @hide
23670 * @cfg {String} msgFx @hide
23673 * @cfg {String} validateOnBlur @hide
23677 Roo.HtmlEditorCore.white = [
23678 'area', 'br', 'img', 'input', 'hr', 'wbr',
23680 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23681 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23682 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23683 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23684 'table', 'ul', 'xmp',
23686 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23689 'dir', 'menu', 'ol', 'ul', 'dl',
23695 Roo.HtmlEditorCore.black = [
23696 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23698 'base', 'basefont', 'bgsound', 'blink', 'body',
23699 'frame', 'frameset', 'head', 'html', 'ilayer',
23700 'iframe', 'layer', 'link', 'meta', 'object',
23701 'script', 'style' ,'title', 'xml' // clean later..
23703 Roo.HtmlEditorCore.clean = [
23704 'script', 'style', 'title', 'xml'
23706 Roo.HtmlEditorCore.remove = [
23711 Roo.HtmlEditorCore.ablack = [
23715 Roo.HtmlEditorCore.aclean = [
23716 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23720 Roo.HtmlEditorCore.pwhite= [
23721 'http', 'https', 'mailto'
23724 // white listed style attributes.
23725 Roo.HtmlEditorCore.cwhite= [
23726 // 'text-align', /// default is to allow most things..
23732 // black listed style attributes.
23733 Roo.HtmlEditorCore.cblack= [
23734 // 'font-size' -- this can be set by the project
23738 Roo.HtmlEditorCore.swapCodes =[
23757 * @class Roo.bootstrap.HtmlEditor
23758 * @extends Roo.bootstrap.TextArea
23759 * Bootstrap HtmlEditor class
23762 * Create a new HtmlEditor
23763 * @param {Object} config The config object
23766 Roo.bootstrap.HtmlEditor = function(config){
23767 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23768 if (!this.toolbars) {
23769 this.toolbars = [];
23772 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23775 * @event initialize
23776 * Fires when the editor is fully initialized (including the iframe)
23777 * @param {HtmlEditor} this
23782 * Fires when the editor is first receives the focus. Any insertion must wait
23783 * until after this event.
23784 * @param {HtmlEditor} this
23788 * @event beforesync
23789 * Fires before the textarea is updated with content from the editor iframe. Return false
23790 * to cancel the sync.
23791 * @param {HtmlEditor} this
23792 * @param {String} html
23796 * @event beforepush
23797 * Fires before the iframe editor is updated with content from the textarea. Return false
23798 * to cancel the push.
23799 * @param {HtmlEditor} this
23800 * @param {String} html
23805 * Fires when the textarea is updated with content from the editor iframe.
23806 * @param {HtmlEditor} this
23807 * @param {String} html
23812 * Fires when the iframe editor is updated with content from the textarea.
23813 * @param {HtmlEditor} this
23814 * @param {String} html
23818 * @event editmodechange
23819 * Fires when the editor switches edit modes
23820 * @param {HtmlEditor} this
23821 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23823 editmodechange: true,
23825 * @event editorevent
23826 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23827 * @param {HtmlEditor} this
23831 * @event firstfocus
23832 * Fires when on first focus - needed by toolbars..
23833 * @param {HtmlEditor} this
23838 * Auto save the htmlEditor value as a file into Events
23839 * @param {HtmlEditor} this
23843 * @event savedpreview
23844 * preview the saved version of htmlEditor
23845 * @param {HtmlEditor} this
23852 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23856 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23861 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23866 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23871 * @cfg {Number} height (in pixels)
23875 * @cfg {Number} width (in pixels)
23880 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23883 stylesheets: false,
23888 // private properties
23889 validationEvent : false,
23891 initialized : false,
23894 onFocus : Roo.emptyFn,
23896 hideMode:'offsets',
23898 tbContainer : false,
23902 toolbarContainer :function() {
23903 return this.wrap.select('.x-html-editor-tb',true).first();
23907 * Protected method that will not generally be called directly. It
23908 * is called when the editor creates its toolbar. Override this method if you need to
23909 * add custom toolbar buttons.
23910 * @param {HtmlEditor} editor
23912 createToolbar : function(){
23913 Roo.log('renewing');
23914 Roo.log("create toolbars");
23916 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23917 this.toolbars[0].render(this.toolbarContainer());
23921 // if (!editor.toolbars || !editor.toolbars.length) {
23922 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23925 // for (var i =0 ; i < editor.toolbars.length;i++) {
23926 // editor.toolbars[i] = Roo.factory(
23927 // typeof(editor.toolbars[i]) == 'string' ?
23928 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23929 // Roo.bootstrap.HtmlEditor);
23930 // editor.toolbars[i].init(editor);
23936 onRender : function(ct, position)
23938 // Roo.log("Call onRender: " + this.xtype);
23940 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23942 this.wrap = this.inputEl().wrap({
23943 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23946 this.editorcore.onRender(ct, position);
23948 if (this.resizable) {
23949 this.resizeEl = new Roo.Resizable(this.wrap, {
23953 minHeight : this.height,
23954 height: this.height,
23955 handles : this.resizable,
23958 resize : function(r, w, h) {
23959 _t.onResize(w,h); // -something
23965 this.createToolbar(this);
23968 if(!this.width && this.resizable){
23969 this.setSize(this.wrap.getSize());
23971 if (this.resizeEl) {
23972 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23973 // should trigger onReize..
23979 onResize : function(w, h)
23981 Roo.log('resize: ' +w + ',' + h );
23982 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23986 if(this.inputEl() ){
23987 if(typeof w == 'number'){
23988 var aw = w - this.wrap.getFrameWidth('lr');
23989 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23992 if(typeof h == 'number'){
23993 var tbh = -11; // fixme it needs to tool bar size!
23994 for (var i =0; i < this.toolbars.length;i++) {
23995 // fixme - ask toolbars for heights?
23996 tbh += this.toolbars[i].el.getHeight();
23997 //if (this.toolbars[i].footer) {
23998 // tbh += this.toolbars[i].footer.el.getHeight();
24006 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24007 ah -= 5; // knock a few pixes off for look..
24008 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
24012 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
24013 this.editorcore.onResize(ew,eh);
24018 * Toggles the editor between standard and source edit mode.
24019 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24021 toggleSourceEdit : function(sourceEditMode)
24023 this.editorcore.toggleSourceEdit(sourceEditMode);
24025 if(this.editorcore.sourceEditMode){
24026 Roo.log('editor - showing textarea');
24029 // Roo.log(this.syncValue());
24031 this.inputEl().removeClass(['hide', 'x-hidden']);
24032 this.inputEl().dom.removeAttribute('tabIndex');
24033 this.inputEl().focus();
24035 Roo.log('editor - hiding textarea');
24037 // Roo.log(this.pushValue());
24040 this.inputEl().addClass(['hide', 'x-hidden']);
24041 this.inputEl().dom.setAttribute('tabIndex', -1);
24042 //this.deferFocus();
24045 if(this.resizable){
24046 this.setSize(this.wrap.getSize());
24049 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
24052 // private (for BoxComponent)
24053 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24055 // private (for BoxComponent)
24056 getResizeEl : function(){
24060 // private (for BoxComponent)
24061 getPositionEl : function(){
24066 initEvents : function(){
24067 this.originalValue = this.getValue();
24071 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24074 // markInvalid : Roo.emptyFn,
24076 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24079 // clearInvalid : Roo.emptyFn,
24081 setValue : function(v){
24082 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24083 this.editorcore.pushValue();
24088 deferFocus : function(){
24089 this.focus.defer(10, this);
24093 focus : function(){
24094 this.editorcore.focus();
24100 onDestroy : function(){
24106 for (var i =0; i < this.toolbars.length;i++) {
24107 // fixme - ask toolbars for heights?
24108 this.toolbars[i].onDestroy();
24111 this.wrap.dom.innerHTML = '';
24112 this.wrap.remove();
24117 onFirstFocus : function(){
24118 //Roo.log("onFirstFocus");
24119 this.editorcore.onFirstFocus();
24120 for (var i =0; i < this.toolbars.length;i++) {
24121 this.toolbars[i].onFirstFocus();
24127 syncValue : function()
24129 this.editorcore.syncValue();
24132 pushValue : function()
24134 this.editorcore.pushValue();
24138 // hide stuff that is not compatible
24152 * @event specialkey
24156 * @cfg {String} fieldClass @hide
24159 * @cfg {String} focusClass @hide
24162 * @cfg {String} autoCreate @hide
24165 * @cfg {String} inputType @hide
24169 * @cfg {String} invalidText @hide
24172 * @cfg {String} msgFx @hide
24175 * @cfg {String} validateOnBlur @hide
24184 Roo.namespace('Roo.bootstrap.htmleditor');
24186 * @class Roo.bootstrap.HtmlEditorToolbar1
24192 new Roo.bootstrap.HtmlEditor({
24195 new Roo.bootstrap.HtmlEditorToolbar1({
24196 disable : { fonts: 1 , format: 1, ..., ... , ...],
24202 * @cfg {Object} disable List of elements to disable..
24203 * @cfg {Array} btns List of additional buttons.
24207 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24210 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24213 Roo.apply(this, config);
24215 // default disabled, based on 'good practice'..
24216 this.disable = this.disable || {};
24217 Roo.applyIf(this.disable, {
24220 specialElements : true
24222 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24224 this.editor = config.editor;
24225 this.editorcore = config.editor.editorcore;
24227 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24229 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24230 // dont call parent... till later.
24232 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24237 editorcore : false,
24242 "h1","h2","h3","h4","h5","h6",
24244 "abbr", "acronym", "address", "cite", "samp", "var",
24248 onRender : function(ct, position)
24250 // Roo.log("Call onRender: " + this.xtype);
24252 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24254 this.el.dom.style.marginBottom = '0';
24256 var editorcore = this.editorcore;
24257 var editor= this.editor;
24260 var btn = function(id,cmd , toggle, handler, html){
24262 var event = toggle ? 'toggle' : 'click';
24267 xns: Roo.bootstrap,
24271 enableToggle:toggle !== false,
24273 pressed : toggle ? false : null,
24276 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24277 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24283 // var cb_box = function...
24288 xns: Roo.bootstrap,
24293 xns: Roo.bootstrap,
24297 Roo.each(this.formats, function(f) {
24298 style.menu.items.push({
24300 xns: Roo.bootstrap,
24301 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24306 editorcore.insertTag(this.tagname);
24313 children.push(style);
24315 btn('bold',false,true);
24316 btn('italic',false,true);
24317 btn('align-left', 'justifyleft',true);
24318 btn('align-center', 'justifycenter',true);
24319 btn('align-right' , 'justifyright',true);
24320 btn('link', false, false, function(btn) {
24321 //Roo.log("create link?");
24322 var url = prompt(this.createLinkText, this.defaultLinkValue);
24323 if(url && url != 'http:/'+'/'){
24324 this.editorcore.relayCmd('createlink', url);
24327 btn('list','insertunorderedlist',true);
24328 btn('pencil', false,true, function(btn){
24330 this.toggleSourceEdit(btn.pressed);
24333 if (this.editor.btns.length > 0) {
24334 for (var i = 0; i<this.editor.btns.length; i++) {
24335 children.push(this.editor.btns[i]);
24343 xns: Roo.bootstrap,
24348 xns: Roo.bootstrap,
24353 cog.menu.items.push({
24355 xns: Roo.bootstrap,
24356 html : Clean styles,
24361 editorcore.insertTag(this.tagname);
24370 this.xtype = 'NavSimplebar';
24372 for(var i=0;i< children.length;i++) {
24374 this.buttons.add(this.addxtypeChild(children[i]));
24378 editor.on('editorevent', this.updateToolbar, this);
24380 onBtnClick : function(id)
24382 this.editorcore.relayCmd(id);
24383 this.editorcore.focus();
24387 * Protected method that will not generally be called directly. It triggers
24388 * a toolbar update by reading the markup state of the current selection in the editor.
24390 updateToolbar: function(){
24392 if(!this.editorcore.activated){
24393 this.editor.onFirstFocus(); // is this neeed?
24397 var btns = this.buttons;
24398 var doc = this.editorcore.doc;
24399 btns.get('bold').setActive(doc.queryCommandState('bold'));
24400 btns.get('italic').setActive(doc.queryCommandState('italic'));
24401 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24403 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24404 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24405 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24407 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24408 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24411 var ans = this.editorcore.getAllAncestors();
24412 if (this.formatCombo) {
24415 var store = this.formatCombo.store;
24416 this.formatCombo.setValue("");
24417 for (var i =0; i < ans.length;i++) {
24418 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24420 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24428 // hides menus... - so this cant be on a menu...
24429 Roo.bootstrap.MenuMgr.hideAll();
24431 Roo.bootstrap.MenuMgr.hideAll();
24432 //this.editorsyncValue();
24434 onFirstFocus: function() {
24435 this.buttons.each(function(item){
24439 toggleSourceEdit : function(sourceEditMode){
24442 if(sourceEditMode){
24443 Roo.log("disabling buttons");
24444 this.buttons.each( function(item){
24445 if(item.cmd != 'pencil'){
24451 Roo.log("enabling buttons");
24452 if(this.editorcore.initialized){
24453 this.buttons.each( function(item){
24459 Roo.log("calling toggole on editor");
24460 // tell the editor that it's been pressed..
24461 this.editor.toggleSourceEdit(sourceEditMode);
24471 * @class Roo.bootstrap.Table.AbstractSelectionModel
24472 * @extends Roo.util.Observable
24473 * Abstract base class for grid SelectionModels. It provides the interface that should be
24474 * implemented by descendant classes. This class should not be directly instantiated.
24477 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24478 this.locked = false;
24479 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24483 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24484 /** @ignore Called by the grid automatically. Do not call directly. */
24485 init : function(grid){
24491 * Locks the selections.
24494 this.locked = true;
24498 * Unlocks the selections.
24500 unlock : function(){
24501 this.locked = false;
24505 * Returns true if the selections are locked.
24506 * @return {Boolean}
24508 isLocked : function(){
24509 return this.locked;
24513 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24514 * @class Roo.bootstrap.Table.RowSelectionModel
24515 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24516 * It supports multiple selections and keyboard selection/navigation.
24518 * @param {Object} config
24521 Roo.bootstrap.Table.RowSelectionModel = function(config){
24522 Roo.apply(this, config);
24523 this.selections = new Roo.util.MixedCollection(false, function(o){
24528 this.lastActive = false;
24532 * @event selectionchange
24533 * Fires when the selection changes
24534 * @param {SelectionModel} this
24536 "selectionchange" : true,
24538 * @event afterselectionchange
24539 * Fires after the selection changes (eg. by key press or clicking)
24540 * @param {SelectionModel} this
24542 "afterselectionchange" : true,
24544 * @event beforerowselect
24545 * Fires when a row is selected being selected, return false to cancel.
24546 * @param {SelectionModel} this
24547 * @param {Number} rowIndex The selected index
24548 * @param {Boolean} keepExisting False if other selections will be cleared
24550 "beforerowselect" : true,
24553 * Fires when a row is selected.
24554 * @param {SelectionModel} this
24555 * @param {Number} rowIndex The selected index
24556 * @param {Roo.data.Record} r The record
24558 "rowselect" : true,
24560 * @event rowdeselect
24561 * Fires when a row is deselected.
24562 * @param {SelectionModel} this
24563 * @param {Number} rowIndex The selected index
24565 "rowdeselect" : true
24567 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24568 this.locked = false;
24571 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24573 * @cfg {Boolean} singleSelect
24574 * True to allow selection of only one row at a time (defaults to false)
24576 singleSelect : false,
24579 initEvents : function()
24582 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24583 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24584 //}else{ // allow click to work like normal
24585 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24587 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24588 this.grid.on("rowclick", this.handleMouseDown, this);
24590 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24591 "up" : function(e){
24593 this.selectPrevious(e.shiftKey);
24594 }else if(this.last !== false && this.lastActive !== false){
24595 var last = this.last;
24596 this.selectRange(this.last, this.lastActive-1);
24597 this.grid.getView().focusRow(this.lastActive);
24598 if(last !== false){
24602 this.selectFirstRow();
24604 this.fireEvent("afterselectionchange", this);
24606 "down" : function(e){
24608 this.selectNext(e.shiftKey);
24609 }else if(this.last !== false && this.lastActive !== false){
24610 var last = this.last;
24611 this.selectRange(this.last, this.lastActive+1);
24612 this.grid.getView().focusRow(this.lastActive);
24613 if(last !== false){
24617 this.selectFirstRow();
24619 this.fireEvent("afterselectionchange", this);
24623 this.grid.store.on('load', function(){
24624 this.selections.clear();
24627 var view = this.grid.view;
24628 view.on("refresh", this.onRefresh, this);
24629 view.on("rowupdated", this.onRowUpdated, this);
24630 view.on("rowremoved", this.onRemove, this);
24635 onRefresh : function()
24637 var ds = this.grid.store, i, v = this.grid.view;
24638 var s = this.selections;
24639 s.each(function(r){
24640 if((i = ds.indexOfId(r.id)) != -1){
24649 onRemove : function(v, index, r){
24650 this.selections.remove(r);
24654 onRowUpdated : function(v, index, r){
24655 if(this.isSelected(r)){
24656 v.onRowSelect(index);
24662 * @param {Array} records The records to select
24663 * @param {Boolean} keepExisting (optional) True to keep existing selections
24665 selectRecords : function(records, keepExisting)
24668 this.clearSelections();
24670 var ds = this.grid.store;
24671 for(var i = 0, len = records.length; i < len; i++){
24672 this.selectRow(ds.indexOf(records[i]), true);
24677 * Gets the number of selected rows.
24680 getCount : function(){
24681 return this.selections.length;
24685 * Selects the first row in the grid.
24687 selectFirstRow : function(){
24692 * Select the last row.
24693 * @param {Boolean} keepExisting (optional) True to keep existing selections
24695 selectLastRow : function(keepExisting){
24696 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24697 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24701 * Selects the row immediately following the last selected row.
24702 * @param {Boolean} keepExisting (optional) True to keep existing selections
24704 selectNext : function(keepExisting)
24706 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24707 this.selectRow(this.last+1, keepExisting);
24708 this.grid.getView().focusRow(this.last);
24713 * Selects the row that precedes the last selected row.
24714 * @param {Boolean} keepExisting (optional) True to keep existing selections
24716 selectPrevious : function(keepExisting){
24718 this.selectRow(this.last-1, keepExisting);
24719 this.grid.getView().focusRow(this.last);
24724 * Returns the selected records
24725 * @return {Array} Array of selected records
24727 getSelections : function(){
24728 return [].concat(this.selections.items);
24732 * Returns the first selected record.
24735 getSelected : function(){
24736 return this.selections.itemAt(0);
24741 * Clears all selections.
24743 clearSelections : function(fast)
24749 var ds = this.grid.store;
24750 var s = this.selections;
24751 s.each(function(r){
24752 this.deselectRow(ds.indexOfId(r.id));
24756 this.selections.clear();
24763 * Selects all rows.
24765 selectAll : function(){
24769 this.selections.clear();
24770 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24771 this.selectRow(i, true);
24776 * Returns True if there is a selection.
24777 * @return {Boolean}
24779 hasSelection : function(){
24780 return this.selections.length > 0;
24784 * Returns True if the specified row is selected.
24785 * @param {Number/Record} record The record or index of the record to check
24786 * @return {Boolean}
24788 isSelected : function(index){
24789 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24790 return (r && this.selections.key(r.id) ? true : false);
24794 * Returns True if the specified record id is selected.
24795 * @param {String} id The id of record to check
24796 * @return {Boolean}
24798 isIdSelected : function(id){
24799 return (this.selections.key(id) ? true : false);
24804 handleMouseDBClick : function(e, t){
24808 handleMouseDown : function(e, t)
24810 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24811 if(this.isLocked() || rowIndex < 0 ){
24814 if(e.shiftKey && this.last !== false){
24815 var last = this.last;
24816 this.selectRange(last, rowIndex, e.ctrlKey);
24817 this.last = last; // reset the last
24821 var isSelected = this.isSelected(rowIndex);
24822 //Roo.log("select row:" + rowIndex);
24824 this.deselectRow(rowIndex);
24826 this.selectRow(rowIndex, true);
24830 if(e.button !== 0 && isSelected){
24831 alert('rowIndex 2: ' + rowIndex);
24832 view.focusRow(rowIndex);
24833 }else if(e.ctrlKey && isSelected){
24834 this.deselectRow(rowIndex);
24835 }else if(!isSelected){
24836 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24837 view.focusRow(rowIndex);
24841 this.fireEvent("afterselectionchange", this);
24844 handleDragableRowClick : function(grid, rowIndex, e)
24846 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24847 this.selectRow(rowIndex, false);
24848 grid.view.focusRow(rowIndex);
24849 this.fireEvent("afterselectionchange", this);
24854 * Selects multiple rows.
24855 * @param {Array} rows Array of the indexes of the row to select
24856 * @param {Boolean} keepExisting (optional) True to keep existing selections
24858 selectRows : function(rows, keepExisting){
24860 this.clearSelections();
24862 for(var i = 0, len = rows.length; i < len; i++){
24863 this.selectRow(rows[i], true);
24868 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24869 * @param {Number} startRow The index of the first row in the range
24870 * @param {Number} endRow The index of the last row in the range
24871 * @param {Boolean} keepExisting (optional) True to retain existing selections
24873 selectRange : function(startRow, endRow, keepExisting){
24878 this.clearSelections();
24880 if(startRow <= endRow){
24881 for(var i = startRow; i <= endRow; i++){
24882 this.selectRow(i, true);
24885 for(var i = startRow; i >= endRow; i--){
24886 this.selectRow(i, true);
24892 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24893 * @param {Number} startRow The index of the first row in the range
24894 * @param {Number} endRow The index of the last row in the range
24896 deselectRange : function(startRow, endRow, preventViewNotify){
24900 for(var i = startRow; i <= endRow; i++){
24901 this.deselectRow(i, preventViewNotify);
24907 * @param {Number} row The index of the row to select
24908 * @param {Boolean} keepExisting (optional) True to keep existing selections
24910 selectRow : function(index, keepExisting, preventViewNotify)
24912 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24915 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24916 if(!keepExisting || this.singleSelect){
24917 this.clearSelections();
24920 var r = this.grid.store.getAt(index);
24921 //console.log('selectRow - record id :' + r.id);
24923 this.selections.add(r);
24924 this.last = this.lastActive = index;
24925 if(!preventViewNotify){
24926 var proxy = new Roo.Element(
24927 this.grid.getRowDom(index)
24929 proxy.addClass('bg-info info');
24931 this.fireEvent("rowselect", this, index, r);
24932 this.fireEvent("selectionchange", this);
24938 * @param {Number} row The index of the row to deselect
24940 deselectRow : function(index, preventViewNotify)
24945 if(this.last == index){
24948 if(this.lastActive == index){
24949 this.lastActive = false;
24952 var r = this.grid.store.getAt(index);
24957 this.selections.remove(r);
24958 //.console.log('deselectRow - record id :' + r.id);
24959 if(!preventViewNotify){
24961 var proxy = new Roo.Element(
24962 this.grid.getRowDom(index)
24964 proxy.removeClass('bg-info info');
24966 this.fireEvent("rowdeselect", this, index);
24967 this.fireEvent("selectionchange", this);
24971 restoreLast : function(){
24973 this.last = this._last;
24978 acceptsNav : function(row, col, cm){
24979 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24983 onEditorKey : function(field, e){
24984 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24989 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24991 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24993 }else if(k == e.ENTER && !e.ctrlKey){
24997 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24999 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
25001 }else if(k == e.ESC){
25005 g.startEditing(newCell[0], newCell[1]);
25011 * Ext JS Library 1.1.1
25012 * Copyright(c) 2006-2007, Ext JS, LLC.
25014 * Originally Released Under LGPL - original licence link has changed is not relivant.
25017 * <script type="text/javascript">
25021 * @class Roo.bootstrap.PagingToolbar
25022 * @extends Roo.bootstrap.NavSimplebar
25023 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
25025 * Create a new PagingToolbar
25026 * @param {Object} config The config object
25027 * @param {Roo.data.Store} store
25029 Roo.bootstrap.PagingToolbar = function(config)
25031 // old args format still supported... - xtype is prefered..
25032 // created from xtype...
25034 this.ds = config.dataSource;
25036 if (config.store && !this.ds) {
25037 this.store= Roo.factory(config.store, Roo.data);
25038 this.ds = this.store;
25039 this.ds.xmodule = this.xmodule || false;
25042 this.toolbarItems = [];
25043 if (config.items) {
25044 this.toolbarItems = config.items;
25047 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
25052 this.bind(this.ds);
25055 if (Roo.bootstrap.version == 4) {
25056 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
25058 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
25063 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
25065 * @cfg {Roo.data.Store} dataSource
25066 * The underlying data store providing the paged data
25069 * @cfg {String/HTMLElement/Element} container
25070 * container The id or element that will contain the toolbar
25073 * @cfg {Boolean} displayInfo
25074 * True to display the displayMsg (defaults to false)
25077 * @cfg {Number} pageSize
25078 * The number of records to display per page (defaults to 20)
25082 * @cfg {String} displayMsg
25083 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25085 displayMsg : 'Displaying {0} - {1} of {2}',
25087 * @cfg {String} emptyMsg
25088 * The message to display when no records are found (defaults to "No data to display")
25090 emptyMsg : 'No data to display',
25092 * Customizable piece of the default paging text (defaults to "Page")
25095 beforePageText : "Page",
25097 * Customizable piece of the default paging text (defaults to "of %0")
25100 afterPageText : "of {0}",
25102 * Customizable piece of the default paging text (defaults to "First Page")
25105 firstText : "First Page",
25107 * Customizable piece of the default paging text (defaults to "Previous Page")
25110 prevText : "Previous Page",
25112 * Customizable piece of the default paging text (defaults to "Next Page")
25115 nextText : "Next Page",
25117 * Customizable piece of the default paging text (defaults to "Last Page")
25120 lastText : "Last Page",
25122 * Customizable piece of the default paging text (defaults to "Refresh")
25125 refreshText : "Refresh",
25129 onRender : function(ct, position)
25131 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25132 this.navgroup.parentId = this.id;
25133 this.navgroup.onRender(this.el, null);
25134 // add the buttons to the navgroup
25136 if(this.displayInfo){
25137 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25138 this.displayEl = this.el.select('.x-paging-info', true).first();
25139 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25140 // this.displayEl = navel.el.select('span',true).first();
25146 Roo.each(_this.buttons, function(e){ // this might need to use render????
25147 Roo.factory(e).render(_this.el);
25151 Roo.each(_this.toolbarItems, function(e) {
25152 _this.navgroup.addItem(e);
25156 this.first = this.navgroup.addItem({
25157 tooltip: this.firstText,
25158 cls: "prev btn-outline-secondary",
25159 html : ' <i class="fa fa-step-backward"></i>',
25161 preventDefault: true,
25162 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25165 this.prev = this.navgroup.addItem({
25166 tooltip: this.prevText,
25167 cls: "prev btn-outline-secondary",
25168 html : ' <i class="fa fa-backward"></i>',
25170 preventDefault: true,
25171 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25173 //this.addSeparator();
25176 var field = this.navgroup.addItem( {
25178 cls : 'x-paging-position btn-outline-secondary',
25180 html : this.beforePageText +
25181 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25182 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25185 this.field = field.el.select('input', true).first();
25186 this.field.on("keydown", this.onPagingKeydown, this);
25187 this.field.on("focus", function(){this.dom.select();});
25190 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25191 //this.field.setHeight(18);
25192 //this.addSeparator();
25193 this.next = this.navgroup.addItem({
25194 tooltip: this.nextText,
25195 cls: "next btn-outline-secondary",
25196 html : ' <i class="fa fa-forward"></i>',
25198 preventDefault: true,
25199 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25201 this.last = this.navgroup.addItem({
25202 tooltip: this.lastText,
25203 html : ' <i class="fa fa-step-forward"></i>',
25204 cls: "next btn-outline-secondary",
25206 preventDefault: true,
25207 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25209 //this.addSeparator();
25210 this.loading = this.navgroup.addItem({
25211 tooltip: this.refreshText,
25212 cls: "btn-outline-secondary",
25213 html : ' <i class="fa fa-refresh"></i>',
25214 preventDefault: true,
25215 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25221 updateInfo : function(){
25222 if(this.displayEl){
25223 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25224 var msg = count == 0 ?
25228 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25230 this.displayEl.update(msg);
25235 onLoad : function(ds, r, o)
25237 this.cursor = o.params.start ? o.params.start : 0;
25239 var d = this.getPageData(),
25244 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25245 this.field.dom.value = ap;
25246 this.first.setDisabled(ap == 1);
25247 this.prev.setDisabled(ap == 1);
25248 this.next.setDisabled(ap == ps);
25249 this.last.setDisabled(ap == ps);
25250 this.loading.enable();
25255 getPageData : function(){
25256 var total = this.ds.getTotalCount();
25259 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25260 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25265 onLoadError : function(){
25266 this.loading.enable();
25270 onPagingKeydown : function(e){
25271 var k = e.getKey();
25272 var d = this.getPageData();
25274 var v = this.field.dom.value, pageNum;
25275 if(!v || isNaN(pageNum = parseInt(v, 10))){
25276 this.field.dom.value = d.activePage;
25279 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25280 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25283 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))
25285 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25286 this.field.dom.value = pageNum;
25287 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25290 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25292 var v = this.field.dom.value, pageNum;
25293 var increment = (e.shiftKey) ? 10 : 1;
25294 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25297 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25298 this.field.dom.value = d.activePage;
25301 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25303 this.field.dom.value = parseInt(v, 10) + increment;
25304 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25305 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25312 beforeLoad : function(){
25314 this.loading.disable();
25319 onClick : function(which){
25328 ds.load({params:{start: 0, limit: this.pageSize}});
25331 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25334 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25337 var total = ds.getTotalCount();
25338 var extra = total % this.pageSize;
25339 var lastStart = extra ? (total - extra) : total-this.pageSize;
25340 ds.load({params:{start: lastStart, limit: this.pageSize}});
25343 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25349 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25350 * @param {Roo.data.Store} store The data store to unbind
25352 unbind : function(ds){
25353 ds.un("beforeload", this.beforeLoad, this);
25354 ds.un("load", this.onLoad, this);
25355 ds.un("loadexception", this.onLoadError, this);
25356 ds.un("remove", this.updateInfo, this);
25357 ds.un("add", this.updateInfo, this);
25358 this.ds = undefined;
25362 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25363 * @param {Roo.data.Store} store The data store to bind
25365 bind : function(ds){
25366 ds.on("beforeload", this.beforeLoad, this);
25367 ds.on("load", this.onLoad, this);
25368 ds.on("loadexception", this.onLoadError, this);
25369 ds.on("remove", this.updateInfo, this);
25370 ds.on("add", this.updateInfo, this);
25381 * @class Roo.bootstrap.MessageBar
25382 * @extends Roo.bootstrap.Component
25383 * Bootstrap MessageBar class
25384 * @cfg {String} html contents of the MessageBar
25385 * @cfg {String} weight (info | success | warning | danger) default info
25386 * @cfg {String} beforeClass insert the bar before the given class
25387 * @cfg {Boolean} closable (true | false) default false
25388 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25391 * Create a new Element
25392 * @param {Object} config The config object
25395 Roo.bootstrap.MessageBar = function(config){
25396 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25399 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25405 beforeClass: 'bootstrap-sticky-wrap',
25407 getAutoCreate : function(){
25411 cls: 'alert alert-dismissable alert-' + this.weight,
25416 html: this.html || ''
25422 cfg.cls += ' alert-messages-fixed';
25436 onRender : function(ct, position)
25438 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25441 var cfg = Roo.apply({}, this.getAutoCreate());
25445 cfg.cls += ' ' + this.cls;
25448 cfg.style = this.style;
25450 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25452 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25455 this.el.select('>button.close').on('click', this.hide, this);
25461 if (!this.rendered) {
25467 this.fireEvent('show', this);
25473 if (!this.rendered) {
25479 this.fireEvent('hide', this);
25482 update : function()
25484 // var e = this.el.dom.firstChild;
25486 // if(this.closable){
25487 // e = e.nextSibling;
25490 // e.data = this.html || '';
25492 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25508 * @class Roo.bootstrap.Graph
25509 * @extends Roo.bootstrap.Component
25510 * Bootstrap Graph class
25514 @cfg {String} graphtype bar | vbar | pie
25515 @cfg {number} g_x coodinator | centre x (pie)
25516 @cfg {number} g_y coodinator | centre y (pie)
25517 @cfg {number} g_r radius (pie)
25518 @cfg {number} g_height height of the chart (respected by all elements in the set)
25519 @cfg {number} g_width width of the chart (respected by all elements in the set)
25520 @cfg {Object} title The title of the chart
25523 -opts (object) options for the chart
25525 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25526 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25528 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.
25529 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25531 o stretch (boolean)
25533 -opts (object) options for the pie
25536 o startAngle (number)
25537 o endAngle (number)
25541 * Create a new Input
25542 * @param {Object} config The config object
25545 Roo.bootstrap.Graph = function(config){
25546 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25552 * The img click event for the img.
25553 * @param {Roo.EventObject} e
25559 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25570 //g_colors: this.colors,
25577 getAutoCreate : function(){
25588 onRender : function(ct,position){
25591 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25593 if (typeof(Raphael) == 'undefined') {
25594 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25598 this.raphael = Raphael(this.el.dom);
25600 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25601 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25602 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25603 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25605 r.text(160, 10, "Single Series Chart").attr(txtattr);
25606 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25607 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25608 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25610 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25611 r.barchart(330, 10, 300, 220, data1);
25612 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25613 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25616 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25617 // r.barchart(30, 30, 560, 250, xdata, {
25618 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25619 // axis : "0 0 1 1",
25620 // axisxlabels : xdata
25621 // //yvalues : cols,
25624 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25626 // this.load(null,xdata,{
25627 // axis : "0 0 1 1",
25628 // axisxlabels : xdata
25633 load : function(graphtype,xdata,opts)
25635 this.raphael.clear();
25637 graphtype = this.graphtype;
25642 var r = this.raphael,
25643 fin = function () {
25644 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25646 fout = function () {
25647 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25649 pfin = function() {
25650 this.sector.stop();
25651 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25654 this.label[0].stop();
25655 this.label[0].attr({ r: 7.5 });
25656 this.label[1].attr({ "font-weight": 800 });
25659 pfout = function() {
25660 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25663 this.label[0].animate({ r: 5 }, 500, "bounce");
25664 this.label[1].attr({ "font-weight": 400 });
25670 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25673 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25676 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25677 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25679 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25686 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25691 setTitle: function(o)
25696 initEvents: function() {
25699 this.el.on('click', this.onClick, this);
25703 onClick : function(e)
25705 Roo.log('img onclick');
25706 this.fireEvent('click', this, e);
25718 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25721 * @class Roo.bootstrap.dash.NumberBox
25722 * @extends Roo.bootstrap.Component
25723 * Bootstrap NumberBox class
25724 * @cfg {String} headline Box headline
25725 * @cfg {String} content Box content
25726 * @cfg {String} icon Box icon
25727 * @cfg {String} footer Footer text
25728 * @cfg {String} fhref Footer href
25731 * Create a new NumberBox
25732 * @param {Object} config The config object
25736 Roo.bootstrap.dash.NumberBox = function(config){
25737 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25741 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25750 getAutoCreate : function(){
25754 cls : 'small-box ',
25762 cls : 'roo-headline',
25763 html : this.headline
25767 cls : 'roo-content',
25768 html : this.content
25782 cls : 'ion ' + this.icon
25791 cls : 'small-box-footer',
25792 href : this.fhref || '#',
25796 cfg.cn.push(footer);
25803 onRender : function(ct,position){
25804 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25811 setHeadline: function (value)
25813 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25816 setFooter: function (value, href)
25818 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25821 this.el.select('a.small-box-footer',true).first().attr('href', href);
25826 setContent: function (value)
25828 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25831 initEvents: function()
25845 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25848 * @class Roo.bootstrap.dash.TabBox
25849 * @extends Roo.bootstrap.Component
25850 * Bootstrap TabBox class
25851 * @cfg {String} title Title of the TabBox
25852 * @cfg {String} icon Icon of the TabBox
25853 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25854 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25857 * Create a new TabBox
25858 * @param {Object} config The config object
25862 Roo.bootstrap.dash.TabBox = function(config){
25863 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25868 * When a pane is added
25869 * @param {Roo.bootstrap.dash.TabPane} pane
25873 * @event activatepane
25874 * When a pane is activated
25875 * @param {Roo.bootstrap.dash.TabPane} pane
25877 "activatepane" : true
25885 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25890 tabScrollable : false,
25892 getChildContainer : function()
25894 return this.el.select('.tab-content', true).first();
25897 getAutoCreate : function(){
25901 cls: 'pull-left header',
25909 cls: 'fa ' + this.icon
25915 cls: 'nav nav-tabs pull-right',
25921 if(this.tabScrollable){
25928 cls: 'nav nav-tabs pull-right',
25939 cls: 'nav-tabs-custom',
25944 cls: 'tab-content no-padding',
25952 initEvents : function()
25954 //Roo.log('add add pane handler');
25955 this.on('addpane', this.onAddPane, this);
25958 * Updates the box title
25959 * @param {String} html to set the title to.
25961 setTitle : function(value)
25963 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25965 onAddPane : function(pane)
25967 this.panes.push(pane);
25968 //Roo.log('addpane');
25970 // tabs are rendere left to right..
25971 if(!this.showtabs){
25975 var ctr = this.el.select('.nav-tabs', true).first();
25978 var existing = ctr.select('.nav-tab',true);
25979 var qty = existing.getCount();;
25982 var tab = ctr.createChild({
25984 cls : 'nav-tab' + (qty ? '' : ' active'),
25992 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25995 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25997 pane.el.addClass('active');
26002 onTabClick : function(ev,un,ob,pane)
26004 //Roo.log('tab - prev default');
26005 ev.preventDefault();
26008 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
26009 pane.tab.addClass('active');
26010 //Roo.log(pane.title);
26011 this.getChildContainer().select('.tab-pane',true).removeClass('active');
26012 // technically we should have a deactivate event.. but maybe add later.
26013 // and it should not de-activate the selected tab...
26014 this.fireEvent('activatepane', pane);
26015 pane.el.addClass('active');
26016 pane.fireEvent('activate');
26021 getActivePane : function()
26024 Roo.each(this.panes, function(p) {
26025 if(p.el.hasClass('active')){
26046 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26048 * @class Roo.bootstrap.TabPane
26049 * @extends Roo.bootstrap.Component
26050 * Bootstrap TabPane class
26051 * @cfg {Boolean} active (false | true) Default false
26052 * @cfg {String} title title of panel
26056 * Create a new TabPane
26057 * @param {Object} config The config object
26060 Roo.bootstrap.dash.TabPane = function(config){
26061 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26067 * When a pane is activated
26068 * @param {Roo.bootstrap.dash.TabPane} pane
26075 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26080 // the tabBox that this is attached to.
26083 getAutoCreate : function()
26091 cfg.cls += ' active';
26096 initEvents : function()
26098 //Roo.log('trigger add pane handler');
26099 this.parent().fireEvent('addpane', this)
26103 * Updates the tab title
26104 * @param {String} html to set the title to.
26106 setTitle: function(str)
26112 this.tab.select('a', true).first().dom.innerHTML = str;
26129 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26132 * @class Roo.bootstrap.menu.Menu
26133 * @extends Roo.bootstrap.Component
26134 * Bootstrap Menu class - container for Menu
26135 * @cfg {String} html Text of the menu
26136 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26137 * @cfg {String} icon Font awesome icon
26138 * @cfg {String} pos Menu align to (top | bottom) default bottom
26142 * Create a new Menu
26143 * @param {Object} config The config object
26147 Roo.bootstrap.menu.Menu = function(config){
26148 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26152 * @event beforeshow
26153 * Fires before this menu is displayed
26154 * @param {Roo.bootstrap.menu.Menu} this
26158 * @event beforehide
26159 * Fires before this menu is hidden
26160 * @param {Roo.bootstrap.menu.Menu} this
26165 * Fires after this menu is displayed
26166 * @param {Roo.bootstrap.menu.Menu} this
26171 * Fires after this menu is hidden
26172 * @param {Roo.bootstrap.menu.Menu} this
26177 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26178 * @param {Roo.bootstrap.menu.Menu} this
26179 * @param {Roo.EventObject} e
26186 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26190 weight : 'default',
26195 getChildContainer : function() {
26196 if(this.isSubMenu){
26200 return this.el.select('ul.dropdown-menu', true).first();
26203 getAutoCreate : function()
26208 cls : 'roo-menu-text',
26216 cls : 'fa ' + this.icon
26227 cls : 'dropdown-button btn btn-' + this.weight,
26232 cls : 'dropdown-toggle btn btn-' + this.weight,
26242 cls : 'dropdown-menu'
26248 if(this.pos == 'top'){
26249 cfg.cls += ' dropup';
26252 if(this.isSubMenu){
26255 cls : 'dropdown-menu'
26262 onRender : function(ct, position)
26264 this.isSubMenu = ct.hasClass('dropdown-submenu');
26266 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26269 initEvents : function()
26271 if(this.isSubMenu){
26275 this.hidden = true;
26277 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26278 this.triggerEl.on('click', this.onTriggerPress, this);
26280 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26281 this.buttonEl.on('click', this.onClick, this);
26287 if(this.isSubMenu){
26291 return this.el.select('ul.dropdown-menu', true).first();
26294 onClick : function(e)
26296 this.fireEvent("click", this, e);
26299 onTriggerPress : function(e)
26301 if (this.isVisible()) {
26308 isVisible : function(){
26309 return !this.hidden;
26314 this.fireEvent("beforeshow", this);
26316 this.hidden = false;
26317 this.el.addClass('open');
26319 Roo.get(document).on("mouseup", this.onMouseUp, this);
26321 this.fireEvent("show", this);
26328 this.fireEvent("beforehide", this);
26330 this.hidden = true;
26331 this.el.removeClass('open');
26333 Roo.get(document).un("mouseup", this.onMouseUp);
26335 this.fireEvent("hide", this);
26338 onMouseUp : function()
26352 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26355 * @class Roo.bootstrap.menu.Item
26356 * @extends Roo.bootstrap.Component
26357 * Bootstrap MenuItem class
26358 * @cfg {Boolean} submenu (true | false) default false
26359 * @cfg {String} html text of the item
26360 * @cfg {String} href the link
26361 * @cfg {Boolean} disable (true | false) default false
26362 * @cfg {Boolean} preventDefault (true | false) default true
26363 * @cfg {String} icon Font awesome icon
26364 * @cfg {String} pos Submenu align to (left | right) default right
26368 * Create a new Item
26369 * @param {Object} config The config object
26373 Roo.bootstrap.menu.Item = function(config){
26374 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26378 * Fires when the mouse is hovering over this menu
26379 * @param {Roo.bootstrap.menu.Item} this
26380 * @param {Roo.EventObject} e
26385 * Fires when the mouse exits this menu
26386 * @param {Roo.bootstrap.menu.Item} this
26387 * @param {Roo.EventObject} e
26393 * The raw click event for the entire grid.
26394 * @param {Roo.EventObject} e
26400 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26405 preventDefault: true,
26410 getAutoCreate : function()
26415 cls : 'roo-menu-item-text',
26423 cls : 'fa ' + this.icon
26432 href : this.href || '#',
26439 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26443 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26445 if(this.pos == 'left'){
26446 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26453 initEvents : function()
26455 this.el.on('mouseover', this.onMouseOver, this);
26456 this.el.on('mouseout', this.onMouseOut, this);
26458 this.el.select('a', true).first().on('click', this.onClick, this);
26462 onClick : function(e)
26464 if(this.preventDefault){
26465 e.preventDefault();
26468 this.fireEvent("click", this, e);
26471 onMouseOver : function(e)
26473 if(this.submenu && this.pos == 'left'){
26474 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26477 this.fireEvent("mouseover", this, e);
26480 onMouseOut : function(e)
26482 this.fireEvent("mouseout", this, e);
26494 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26497 * @class Roo.bootstrap.menu.Separator
26498 * @extends Roo.bootstrap.Component
26499 * Bootstrap Separator class
26502 * Create a new Separator
26503 * @param {Object} config The config object
26507 Roo.bootstrap.menu.Separator = function(config){
26508 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26511 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26513 getAutoCreate : function(){
26534 * @class Roo.bootstrap.Tooltip
26535 * Bootstrap Tooltip class
26536 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26537 * to determine which dom element triggers the tooltip.
26539 * It needs to add support for additional attributes like tooltip-position
26542 * Create a new Toolti
26543 * @param {Object} config The config object
26546 Roo.bootstrap.Tooltip = function(config){
26547 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26549 this.alignment = Roo.bootstrap.Tooltip.alignment;
26551 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26552 this.alignment = config.alignment;
26557 Roo.apply(Roo.bootstrap.Tooltip, {
26559 * @function init initialize tooltip monitoring.
26563 currentTip : false,
26564 currentRegion : false,
26570 Roo.get(document).on('mouseover', this.enter ,this);
26571 Roo.get(document).on('mouseout', this.leave, this);
26574 this.currentTip = new Roo.bootstrap.Tooltip();
26577 enter : function(ev)
26579 var dom = ev.getTarget();
26581 //Roo.log(['enter',dom]);
26582 var el = Roo.fly(dom);
26583 if (this.currentEl) {
26585 //Roo.log(this.currentEl);
26586 //Roo.log(this.currentEl.contains(dom));
26587 if (this.currentEl == el) {
26590 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26596 if (this.currentTip.el) {
26597 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26601 if(!el || el.dom == document){
26607 // you can not look for children, as if el is the body.. then everythign is the child..
26608 if (!el.attr('tooltip')) { //
26609 if (!el.select("[tooltip]").elements.length) {
26612 // is the mouse over this child...?
26613 bindEl = el.select("[tooltip]").first();
26614 var xy = ev.getXY();
26615 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26616 //Roo.log("not in region.");
26619 //Roo.log("child element over..");
26622 this.currentEl = bindEl;
26623 this.currentTip.bind(bindEl);
26624 this.currentRegion = Roo.lib.Region.getRegion(dom);
26625 this.currentTip.enter();
26628 leave : function(ev)
26630 var dom = ev.getTarget();
26631 //Roo.log(['leave',dom]);
26632 if (!this.currentEl) {
26637 if (dom != this.currentEl.dom) {
26640 var xy = ev.getXY();
26641 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26644 // only activate leave if mouse cursor is outside... bounding box..
26649 if (this.currentTip) {
26650 this.currentTip.leave();
26652 //Roo.log('clear currentEl');
26653 this.currentEl = false;
26658 'left' : ['r-l', [-2,0], 'right'],
26659 'right' : ['l-r', [2,0], 'left'],
26660 'bottom' : ['t-b', [0,2], 'top'],
26661 'top' : [ 'b-t', [0,-2], 'bottom']
26667 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26672 delay : null, // can be { show : 300 , hide: 500}
26676 hoverState : null, //???
26678 placement : 'bottom',
26682 getAutoCreate : function(){
26689 cls : 'tooltip-arrow'
26692 cls : 'tooltip-inner'
26699 bind : function(el)
26705 enter : function () {
26707 if (this.timeout != null) {
26708 clearTimeout(this.timeout);
26711 this.hoverState = 'in';
26712 //Roo.log("enter - show");
26713 if (!this.delay || !this.delay.show) {
26718 this.timeout = setTimeout(function () {
26719 if (_t.hoverState == 'in') {
26722 }, this.delay.show);
26726 clearTimeout(this.timeout);
26728 this.hoverState = 'out';
26729 if (!this.delay || !this.delay.hide) {
26735 this.timeout = setTimeout(function () {
26736 //Roo.log("leave - timeout");
26738 if (_t.hoverState == 'out') {
26740 Roo.bootstrap.Tooltip.currentEl = false;
26745 show : function (msg)
26748 this.render(document.body);
26751 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26753 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26755 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26757 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26759 var placement = typeof this.placement == 'function' ?
26760 this.placement.call(this, this.el, on_el) :
26763 var autoToken = /\s?auto?\s?/i;
26764 var autoPlace = autoToken.test(placement);
26766 placement = placement.replace(autoToken, '') || 'top';
26770 //this.el.setXY([0,0]);
26772 //this.el.dom.style.display='block';
26774 //this.el.appendTo(on_el);
26776 var p = this.getPosition();
26777 var box = this.el.getBox();
26783 var align = this.alignment[placement];
26785 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26787 if(placement == 'top' || placement == 'bottom'){
26789 placement = 'right';
26792 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26793 placement = 'left';
26796 var scroll = Roo.select('body', true).first().getScroll();
26798 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26802 align = this.alignment[placement];
26805 this.el.alignTo(this.bindEl, align[0],align[1]);
26806 //var arrow = this.el.select('.arrow',true).first();
26807 //arrow.set(align[2],
26809 this.el.addClass(placement);
26811 this.el.addClass('in fade');
26813 this.hoverState = null;
26815 if (this.el.hasClass('fade')) {
26826 //this.el.setXY([0,0]);
26827 this.el.removeClass('in');
26843 * @class Roo.bootstrap.LocationPicker
26844 * @extends Roo.bootstrap.Component
26845 * Bootstrap LocationPicker class
26846 * @cfg {Number} latitude Position when init default 0
26847 * @cfg {Number} longitude Position when init default 0
26848 * @cfg {Number} zoom default 15
26849 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26850 * @cfg {Boolean} mapTypeControl default false
26851 * @cfg {Boolean} disableDoubleClickZoom default false
26852 * @cfg {Boolean} scrollwheel default true
26853 * @cfg {Boolean} streetViewControl default false
26854 * @cfg {Number} radius default 0
26855 * @cfg {String} locationName
26856 * @cfg {Boolean} draggable default true
26857 * @cfg {Boolean} enableAutocomplete default false
26858 * @cfg {Boolean} enableReverseGeocode default true
26859 * @cfg {String} markerTitle
26862 * Create a new LocationPicker
26863 * @param {Object} config The config object
26867 Roo.bootstrap.LocationPicker = function(config){
26869 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26874 * Fires when the picker initialized.
26875 * @param {Roo.bootstrap.LocationPicker} this
26876 * @param {Google Location} location
26880 * @event positionchanged
26881 * Fires when the picker position changed.
26882 * @param {Roo.bootstrap.LocationPicker} this
26883 * @param {Google Location} location
26885 positionchanged : true,
26888 * Fires when the map resize.
26889 * @param {Roo.bootstrap.LocationPicker} this
26894 * Fires when the map show.
26895 * @param {Roo.bootstrap.LocationPicker} this
26900 * Fires when the map hide.
26901 * @param {Roo.bootstrap.LocationPicker} this
26906 * Fires when click the map.
26907 * @param {Roo.bootstrap.LocationPicker} this
26908 * @param {Map event} e
26912 * @event mapRightClick
26913 * Fires when right click the map.
26914 * @param {Roo.bootstrap.LocationPicker} this
26915 * @param {Map event} e
26917 mapRightClick : true,
26919 * @event markerClick
26920 * Fires when click the marker.
26921 * @param {Roo.bootstrap.LocationPicker} this
26922 * @param {Map event} e
26924 markerClick : true,
26926 * @event markerRightClick
26927 * Fires when right click the marker.
26928 * @param {Roo.bootstrap.LocationPicker} this
26929 * @param {Map event} e
26931 markerRightClick : true,
26933 * @event OverlayViewDraw
26934 * Fires when OverlayView Draw
26935 * @param {Roo.bootstrap.LocationPicker} this
26937 OverlayViewDraw : true,
26939 * @event OverlayViewOnAdd
26940 * Fires when OverlayView Draw
26941 * @param {Roo.bootstrap.LocationPicker} this
26943 OverlayViewOnAdd : true,
26945 * @event OverlayViewOnRemove
26946 * Fires when OverlayView Draw
26947 * @param {Roo.bootstrap.LocationPicker} this
26949 OverlayViewOnRemove : true,
26951 * @event OverlayViewShow
26952 * Fires when OverlayView Draw
26953 * @param {Roo.bootstrap.LocationPicker} this
26954 * @param {Pixel} cpx
26956 OverlayViewShow : true,
26958 * @event OverlayViewHide
26959 * Fires when OverlayView Draw
26960 * @param {Roo.bootstrap.LocationPicker} this
26962 OverlayViewHide : true,
26964 * @event loadexception
26965 * Fires when load google lib failed.
26966 * @param {Roo.bootstrap.LocationPicker} this
26968 loadexception : true
26973 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26975 gMapContext: false,
26981 mapTypeControl: false,
26982 disableDoubleClickZoom: false,
26984 streetViewControl: false,
26988 enableAutocomplete: false,
26989 enableReverseGeocode: true,
26992 getAutoCreate: function()
26997 cls: 'roo-location-picker'
27003 initEvents: function(ct, position)
27005 if(!this.el.getWidth() || this.isApplied()){
27009 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27014 initial: function()
27016 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
27017 this.fireEvent('loadexception', this);
27021 if(!this.mapTypeId){
27022 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
27025 this.gMapContext = this.GMapContext();
27027 this.initOverlayView();
27029 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
27033 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
27034 _this.setPosition(_this.gMapContext.marker.position);
27037 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
27038 _this.fireEvent('mapClick', this, event);
27042 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
27043 _this.fireEvent('mapRightClick', this, event);
27047 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
27048 _this.fireEvent('markerClick', this, event);
27052 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
27053 _this.fireEvent('markerRightClick', this, event);
27057 this.setPosition(this.gMapContext.location);
27059 this.fireEvent('initial', this, this.gMapContext.location);
27062 initOverlayView: function()
27066 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27070 _this.fireEvent('OverlayViewDraw', _this);
27075 _this.fireEvent('OverlayViewOnAdd', _this);
27078 onRemove: function()
27080 _this.fireEvent('OverlayViewOnRemove', _this);
27083 show: function(cpx)
27085 _this.fireEvent('OverlayViewShow', _this, cpx);
27090 _this.fireEvent('OverlayViewHide', _this);
27096 fromLatLngToContainerPixel: function(event)
27098 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27101 isApplied: function()
27103 return this.getGmapContext() == false ? false : true;
27106 getGmapContext: function()
27108 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27111 GMapContext: function()
27113 var position = new google.maps.LatLng(this.latitude, this.longitude);
27115 var _map = new google.maps.Map(this.el.dom, {
27118 mapTypeId: this.mapTypeId,
27119 mapTypeControl: this.mapTypeControl,
27120 disableDoubleClickZoom: this.disableDoubleClickZoom,
27121 scrollwheel: this.scrollwheel,
27122 streetViewControl: this.streetViewControl,
27123 locationName: this.locationName,
27124 draggable: this.draggable,
27125 enableAutocomplete: this.enableAutocomplete,
27126 enableReverseGeocode: this.enableReverseGeocode
27129 var _marker = new google.maps.Marker({
27130 position: position,
27132 title: this.markerTitle,
27133 draggable: this.draggable
27140 location: position,
27141 radius: this.radius,
27142 locationName: this.locationName,
27143 addressComponents: {
27144 formatted_address: null,
27145 addressLine1: null,
27146 addressLine2: null,
27148 streetNumber: null,
27152 stateOrProvince: null
27155 domContainer: this.el.dom,
27156 geodecoder: new google.maps.Geocoder()
27160 drawCircle: function(center, radius, options)
27162 if (this.gMapContext.circle != null) {
27163 this.gMapContext.circle.setMap(null);
27167 options = Roo.apply({}, options, {
27168 strokeColor: "#0000FF",
27169 strokeOpacity: .35,
27171 fillColor: "#0000FF",
27175 options.map = this.gMapContext.map;
27176 options.radius = radius;
27177 options.center = center;
27178 this.gMapContext.circle = new google.maps.Circle(options);
27179 return this.gMapContext.circle;
27185 setPosition: function(location)
27187 this.gMapContext.location = location;
27188 this.gMapContext.marker.setPosition(location);
27189 this.gMapContext.map.panTo(location);
27190 this.drawCircle(location, this.gMapContext.radius, {});
27194 if (this.gMapContext.settings.enableReverseGeocode) {
27195 this.gMapContext.geodecoder.geocode({
27196 latLng: this.gMapContext.location
27197 }, function(results, status) {
27199 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27200 _this.gMapContext.locationName = results[0].formatted_address;
27201 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27203 _this.fireEvent('positionchanged', this, location);
27210 this.fireEvent('positionchanged', this, location);
27215 google.maps.event.trigger(this.gMapContext.map, "resize");
27217 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27219 this.fireEvent('resize', this);
27222 setPositionByLatLng: function(latitude, longitude)
27224 this.setPosition(new google.maps.LatLng(latitude, longitude));
27227 getCurrentPosition: function()
27230 latitude: this.gMapContext.location.lat(),
27231 longitude: this.gMapContext.location.lng()
27235 getAddressName: function()
27237 return this.gMapContext.locationName;
27240 getAddressComponents: function()
27242 return this.gMapContext.addressComponents;
27245 address_component_from_google_geocode: function(address_components)
27249 for (var i = 0; i < address_components.length; i++) {
27250 var component = address_components[i];
27251 if (component.types.indexOf("postal_code") >= 0) {
27252 result.postalCode = component.short_name;
27253 } else if (component.types.indexOf("street_number") >= 0) {
27254 result.streetNumber = component.short_name;
27255 } else if (component.types.indexOf("route") >= 0) {
27256 result.streetName = component.short_name;
27257 } else if (component.types.indexOf("neighborhood") >= 0) {
27258 result.city = component.short_name;
27259 } else if (component.types.indexOf("locality") >= 0) {
27260 result.city = component.short_name;
27261 } else if (component.types.indexOf("sublocality") >= 0) {
27262 result.district = component.short_name;
27263 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27264 result.stateOrProvince = component.short_name;
27265 } else if (component.types.indexOf("country") >= 0) {
27266 result.country = component.short_name;
27270 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27271 result.addressLine2 = "";
27275 setZoomLevel: function(zoom)
27277 this.gMapContext.map.setZoom(zoom);
27290 this.fireEvent('show', this);
27301 this.fireEvent('hide', this);
27306 Roo.apply(Roo.bootstrap.LocationPicker, {
27308 OverlayView : function(map, options)
27310 options = options || {};
27317 * @class Roo.bootstrap.Alert
27318 * @extends Roo.bootstrap.Component
27319 * Bootstrap Alert class - shows an alert area box
27321 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27322 Enter a valid email address
27325 * @cfg {String} title The title of alert
27326 * @cfg {String} html The content of alert
27327 * @cfg {String} weight ( success | info | warning | danger )
27328 * @cfg {String} faicon font-awesomeicon
27331 * Create a new alert
27332 * @param {Object} config The config object
27336 Roo.bootstrap.Alert = function(config){
27337 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27341 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27348 getAutoCreate : function()
27357 cls : 'roo-alert-icon'
27362 cls : 'roo-alert-title',
27367 cls : 'roo-alert-text',
27374 cfg.cn[0].cls += ' fa ' + this.faicon;
27378 cfg.cls += ' alert-' + this.weight;
27384 initEvents: function()
27386 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27389 setTitle : function(str)
27391 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27394 setText : function(str)
27396 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27399 setWeight : function(weight)
27402 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27405 this.weight = weight;
27407 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27410 setIcon : function(icon)
27413 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27416 this.faicon = icon;
27418 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27439 * @class Roo.bootstrap.UploadCropbox
27440 * @extends Roo.bootstrap.Component
27441 * Bootstrap UploadCropbox class
27442 * @cfg {String} emptyText show when image has been loaded
27443 * @cfg {String} rotateNotify show when image too small to rotate
27444 * @cfg {Number} errorTimeout default 3000
27445 * @cfg {Number} minWidth default 300
27446 * @cfg {Number} minHeight default 300
27447 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27448 * @cfg {Boolean} isDocument (true|false) default false
27449 * @cfg {String} url action url
27450 * @cfg {String} paramName default 'imageUpload'
27451 * @cfg {String} method default POST
27452 * @cfg {Boolean} loadMask (true|false) default true
27453 * @cfg {Boolean} loadingText default 'Loading...'
27456 * Create a new UploadCropbox
27457 * @param {Object} config The config object
27460 Roo.bootstrap.UploadCropbox = function(config){
27461 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27465 * @event beforeselectfile
27466 * Fire before select file
27467 * @param {Roo.bootstrap.UploadCropbox} this
27469 "beforeselectfile" : true,
27472 * Fire after initEvent
27473 * @param {Roo.bootstrap.UploadCropbox} this
27478 * Fire after initEvent
27479 * @param {Roo.bootstrap.UploadCropbox} this
27480 * @param {String} data
27485 * Fire when preparing the file data
27486 * @param {Roo.bootstrap.UploadCropbox} this
27487 * @param {Object} file
27492 * Fire when get exception
27493 * @param {Roo.bootstrap.UploadCropbox} this
27494 * @param {XMLHttpRequest} xhr
27496 "exception" : true,
27498 * @event beforeloadcanvas
27499 * Fire before load the canvas
27500 * @param {Roo.bootstrap.UploadCropbox} this
27501 * @param {String} src
27503 "beforeloadcanvas" : true,
27506 * Fire when trash image
27507 * @param {Roo.bootstrap.UploadCropbox} this
27512 * Fire when download the image
27513 * @param {Roo.bootstrap.UploadCropbox} this
27517 * @event footerbuttonclick
27518 * Fire when footerbuttonclick
27519 * @param {Roo.bootstrap.UploadCropbox} this
27520 * @param {String} type
27522 "footerbuttonclick" : true,
27526 * @param {Roo.bootstrap.UploadCropbox} this
27531 * Fire when rotate the image
27532 * @param {Roo.bootstrap.UploadCropbox} this
27533 * @param {String} pos
27538 * Fire when inspect the file
27539 * @param {Roo.bootstrap.UploadCropbox} this
27540 * @param {Object} file
27545 * Fire when xhr upload the file
27546 * @param {Roo.bootstrap.UploadCropbox} this
27547 * @param {Object} data
27552 * Fire when arrange the file data
27553 * @param {Roo.bootstrap.UploadCropbox} this
27554 * @param {Object} formData
27559 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27562 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27564 emptyText : 'Click to upload image',
27565 rotateNotify : 'Image is too small to rotate',
27566 errorTimeout : 3000,
27580 cropType : 'image/jpeg',
27582 canvasLoaded : false,
27583 isDocument : false,
27585 paramName : 'imageUpload',
27587 loadingText : 'Loading...',
27590 getAutoCreate : function()
27594 cls : 'roo-upload-cropbox',
27598 cls : 'roo-upload-cropbox-selector',
27603 cls : 'roo-upload-cropbox-body',
27604 style : 'cursor:pointer',
27608 cls : 'roo-upload-cropbox-preview'
27612 cls : 'roo-upload-cropbox-thumb'
27616 cls : 'roo-upload-cropbox-empty-notify',
27617 html : this.emptyText
27621 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27622 html : this.rotateNotify
27628 cls : 'roo-upload-cropbox-footer',
27631 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27641 onRender : function(ct, position)
27643 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27645 if (this.buttons.length) {
27647 Roo.each(this.buttons, function(bb) {
27649 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27651 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27657 this.maskEl = this.el;
27661 initEvents : function()
27663 this.urlAPI = (window.createObjectURL && window) ||
27664 (window.URL && URL.revokeObjectURL && URL) ||
27665 (window.webkitURL && webkitURL);
27667 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27668 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27670 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27671 this.selectorEl.hide();
27673 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27674 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27676 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27677 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27678 this.thumbEl.hide();
27680 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27681 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27683 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27684 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27685 this.errorEl.hide();
27687 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27688 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27689 this.footerEl.hide();
27691 this.setThumbBoxSize();
27697 this.fireEvent('initial', this);
27704 window.addEventListener("resize", function() { _this.resize(); } );
27706 this.bodyEl.on('click', this.beforeSelectFile, this);
27709 this.bodyEl.on('touchstart', this.onTouchStart, this);
27710 this.bodyEl.on('touchmove', this.onTouchMove, this);
27711 this.bodyEl.on('touchend', this.onTouchEnd, this);
27715 this.bodyEl.on('mousedown', this.onMouseDown, this);
27716 this.bodyEl.on('mousemove', this.onMouseMove, this);
27717 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27718 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27719 Roo.get(document).on('mouseup', this.onMouseUp, this);
27722 this.selectorEl.on('change', this.onFileSelected, this);
27728 this.baseScale = 1;
27730 this.baseRotate = 1;
27731 this.dragable = false;
27732 this.pinching = false;
27735 this.cropData = false;
27736 this.notifyEl.dom.innerHTML = this.emptyText;
27738 this.selectorEl.dom.value = '';
27742 resize : function()
27744 if(this.fireEvent('resize', this) != false){
27745 this.setThumbBoxPosition();
27746 this.setCanvasPosition();
27750 onFooterButtonClick : function(e, el, o, type)
27753 case 'rotate-left' :
27754 this.onRotateLeft(e);
27756 case 'rotate-right' :
27757 this.onRotateRight(e);
27760 this.beforeSelectFile(e);
27775 this.fireEvent('footerbuttonclick', this, type);
27778 beforeSelectFile : function(e)
27780 e.preventDefault();
27782 if(this.fireEvent('beforeselectfile', this) != false){
27783 this.selectorEl.dom.click();
27787 onFileSelected : function(e)
27789 e.preventDefault();
27791 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27795 var file = this.selectorEl.dom.files[0];
27797 if(this.fireEvent('inspect', this, file) != false){
27798 this.prepare(file);
27803 trash : function(e)
27805 this.fireEvent('trash', this);
27808 download : function(e)
27810 this.fireEvent('download', this);
27813 loadCanvas : function(src)
27815 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27819 this.imageEl = document.createElement('img');
27823 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27825 this.imageEl.src = src;
27829 onLoadCanvas : function()
27831 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27832 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27834 this.bodyEl.un('click', this.beforeSelectFile, this);
27836 this.notifyEl.hide();
27837 this.thumbEl.show();
27838 this.footerEl.show();
27840 this.baseRotateLevel();
27842 if(this.isDocument){
27843 this.setThumbBoxSize();
27846 this.setThumbBoxPosition();
27848 this.baseScaleLevel();
27854 this.canvasLoaded = true;
27857 this.maskEl.unmask();
27862 setCanvasPosition : function()
27864 if(!this.canvasEl){
27868 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27869 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27871 this.previewEl.setLeft(pw);
27872 this.previewEl.setTop(ph);
27876 onMouseDown : function(e)
27880 this.dragable = true;
27881 this.pinching = false;
27883 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27884 this.dragable = false;
27888 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27889 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27893 onMouseMove : function(e)
27897 if(!this.canvasLoaded){
27901 if (!this.dragable){
27905 var minX = Math.ceil(this.thumbEl.getLeft(true));
27906 var minY = Math.ceil(this.thumbEl.getTop(true));
27908 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27909 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27911 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27912 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27914 x = x - this.mouseX;
27915 y = y - this.mouseY;
27917 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27918 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27920 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27921 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27923 this.previewEl.setLeft(bgX);
27924 this.previewEl.setTop(bgY);
27926 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27927 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27930 onMouseUp : function(e)
27934 this.dragable = false;
27937 onMouseWheel : function(e)
27941 this.startScale = this.scale;
27943 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27945 if(!this.zoomable()){
27946 this.scale = this.startScale;
27955 zoomable : function()
27957 var minScale = this.thumbEl.getWidth() / this.minWidth;
27959 if(this.minWidth < this.minHeight){
27960 minScale = this.thumbEl.getHeight() / this.minHeight;
27963 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27964 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27968 (this.rotate == 0 || this.rotate == 180) &&
27970 width > this.imageEl.OriginWidth ||
27971 height > this.imageEl.OriginHeight ||
27972 (width < this.minWidth && height < this.minHeight)
27980 (this.rotate == 90 || this.rotate == 270) &&
27982 width > this.imageEl.OriginWidth ||
27983 height > this.imageEl.OriginHeight ||
27984 (width < this.minHeight && height < this.minWidth)
27991 !this.isDocument &&
27992 (this.rotate == 0 || this.rotate == 180) &&
27994 width < this.minWidth ||
27995 width > this.imageEl.OriginWidth ||
27996 height < this.minHeight ||
27997 height > this.imageEl.OriginHeight
28004 !this.isDocument &&
28005 (this.rotate == 90 || this.rotate == 270) &&
28007 width < this.minHeight ||
28008 width > this.imageEl.OriginWidth ||
28009 height < this.minWidth ||
28010 height > this.imageEl.OriginHeight
28020 onRotateLeft : function(e)
28022 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28024 var minScale = this.thumbEl.getWidth() / this.minWidth;
28026 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28027 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28029 this.startScale = this.scale;
28031 while (this.getScaleLevel() < minScale){
28033 this.scale = this.scale + 1;
28035 if(!this.zoomable()){
28040 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28041 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28046 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28053 this.scale = this.startScale;
28055 this.onRotateFail();
28060 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28062 if(this.isDocument){
28063 this.setThumbBoxSize();
28064 this.setThumbBoxPosition();
28065 this.setCanvasPosition();
28070 this.fireEvent('rotate', this, 'left');
28074 onRotateRight : function(e)
28076 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28078 var minScale = this.thumbEl.getWidth() / this.minWidth;
28080 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28081 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28083 this.startScale = this.scale;
28085 while (this.getScaleLevel() < minScale){
28087 this.scale = this.scale + 1;
28089 if(!this.zoomable()){
28094 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28095 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28100 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28107 this.scale = this.startScale;
28109 this.onRotateFail();
28114 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28116 if(this.isDocument){
28117 this.setThumbBoxSize();
28118 this.setThumbBoxPosition();
28119 this.setCanvasPosition();
28124 this.fireEvent('rotate', this, 'right');
28127 onRotateFail : function()
28129 this.errorEl.show(true);
28133 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28138 this.previewEl.dom.innerHTML = '';
28140 var canvasEl = document.createElement("canvas");
28142 var contextEl = canvasEl.getContext("2d");
28144 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28145 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28146 var center = this.imageEl.OriginWidth / 2;
28148 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28149 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28150 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28151 center = this.imageEl.OriginHeight / 2;
28154 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28156 contextEl.translate(center, center);
28157 contextEl.rotate(this.rotate * Math.PI / 180);
28159 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28161 this.canvasEl = document.createElement("canvas");
28163 this.contextEl = this.canvasEl.getContext("2d");
28165 switch (this.rotate) {
28168 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28169 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28171 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28176 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28177 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28179 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28180 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);
28184 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28189 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28190 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28192 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28193 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);
28197 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);
28202 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28203 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28205 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28206 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28210 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);
28217 this.previewEl.appendChild(this.canvasEl);
28219 this.setCanvasPosition();
28224 if(!this.canvasLoaded){
28228 var imageCanvas = document.createElement("canvas");
28230 var imageContext = imageCanvas.getContext("2d");
28232 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28233 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28235 var center = imageCanvas.width / 2;
28237 imageContext.translate(center, center);
28239 imageContext.rotate(this.rotate * Math.PI / 180);
28241 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28243 var canvas = document.createElement("canvas");
28245 var context = canvas.getContext("2d");
28247 canvas.width = this.minWidth;
28248 canvas.height = this.minHeight;
28250 switch (this.rotate) {
28253 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28254 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28256 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28257 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28259 var targetWidth = this.minWidth - 2 * x;
28260 var targetHeight = this.minHeight - 2 * y;
28264 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28265 scale = targetWidth / width;
28268 if(x > 0 && y == 0){
28269 scale = targetHeight / height;
28272 if(x > 0 && y > 0){
28273 scale = targetWidth / width;
28275 if(width < height){
28276 scale = targetHeight / height;
28280 context.scale(scale, scale);
28282 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28283 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28285 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28286 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28288 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28293 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28294 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28296 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28297 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28299 var targetWidth = this.minWidth - 2 * x;
28300 var targetHeight = this.minHeight - 2 * y;
28304 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28305 scale = targetWidth / width;
28308 if(x > 0 && y == 0){
28309 scale = targetHeight / height;
28312 if(x > 0 && y > 0){
28313 scale = targetWidth / width;
28315 if(width < height){
28316 scale = targetHeight / height;
28320 context.scale(scale, scale);
28322 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28323 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28325 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28326 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28328 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28330 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28335 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28336 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28338 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28339 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28341 var targetWidth = this.minWidth - 2 * x;
28342 var targetHeight = this.minHeight - 2 * y;
28346 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28347 scale = targetWidth / width;
28350 if(x > 0 && y == 0){
28351 scale = targetHeight / height;
28354 if(x > 0 && y > 0){
28355 scale = targetWidth / width;
28357 if(width < height){
28358 scale = targetHeight / height;
28362 context.scale(scale, scale);
28364 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28365 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28367 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28368 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28370 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28371 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28373 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28378 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28379 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28381 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28382 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28384 var targetWidth = this.minWidth - 2 * x;
28385 var targetHeight = this.minHeight - 2 * y;
28389 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28390 scale = targetWidth / width;
28393 if(x > 0 && y == 0){
28394 scale = targetHeight / height;
28397 if(x > 0 && y > 0){
28398 scale = targetWidth / width;
28400 if(width < height){
28401 scale = targetHeight / height;
28405 context.scale(scale, scale);
28407 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28408 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28410 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28411 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28413 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28415 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28422 this.cropData = canvas.toDataURL(this.cropType);
28424 if(this.fireEvent('crop', this, this.cropData) !== false){
28425 this.process(this.file, this.cropData);
28432 setThumbBoxSize : function()
28436 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28437 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28438 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28440 this.minWidth = width;
28441 this.minHeight = height;
28443 if(this.rotate == 90 || this.rotate == 270){
28444 this.minWidth = height;
28445 this.minHeight = width;
28450 width = Math.ceil(this.minWidth * height / this.minHeight);
28452 if(this.minWidth > this.minHeight){
28454 height = Math.ceil(this.minHeight * width / this.minWidth);
28457 this.thumbEl.setStyle({
28458 width : width + 'px',
28459 height : height + 'px'
28466 setThumbBoxPosition : function()
28468 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28469 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28471 this.thumbEl.setLeft(x);
28472 this.thumbEl.setTop(y);
28476 baseRotateLevel : function()
28478 this.baseRotate = 1;
28481 typeof(this.exif) != 'undefined' &&
28482 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28483 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28485 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28488 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28492 baseScaleLevel : function()
28496 if(this.isDocument){
28498 if(this.baseRotate == 6 || this.baseRotate == 8){
28500 height = this.thumbEl.getHeight();
28501 this.baseScale = height / this.imageEl.OriginWidth;
28503 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28504 width = this.thumbEl.getWidth();
28505 this.baseScale = width / this.imageEl.OriginHeight;
28511 height = this.thumbEl.getHeight();
28512 this.baseScale = height / this.imageEl.OriginHeight;
28514 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28515 width = this.thumbEl.getWidth();
28516 this.baseScale = width / this.imageEl.OriginWidth;
28522 if(this.baseRotate == 6 || this.baseRotate == 8){
28524 width = this.thumbEl.getHeight();
28525 this.baseScale = width / this.imageEl.OriginHeight;
28527 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28528 height = this.thumbEl.getWidth();
28529 this.baseScale = height / this.imageEl.OriginHeight;
28532 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28533 height = this.thumbEl.getWidth();
28534 this.baseScale = height / this.imageEl.OriginHeight;
28536 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28537 width = this.thumbEl.getHeight();
28538 this.baseScale = width / this.imageEl.OriginWidth;
28545 width = this.thumbEl.getWidth();
28546 this.baseScale = width / this.imageEl.OriginWidth;
28548 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28549 height = this.thumbEl.getHeight();
28550 this.baseScale = height / this.imageEl.OriginHeight;
28553 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28555 height = this.thumbEl.getHeight();
28556 this.baseScale = height / this.imageEl.OriginHeight;
28558 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28559 width = this.thumbEl.getWidth();
28560 this.baseScale = width / this.imageEl.OriginWidth;
28568 getScaleLevel : function()
28570 return this.baseScale * Math.pow(1.1, this.scale);
28573 onTouchStart : function(e)
28575 if(!this.canvasLoaded){
28576 this.beforeSelectFile(e);
28580 var touches = e.browserEvent.touches;
28586 if(touches.length == 1){
28587 this.onMouseDown(e);
28591 if(touches.length != 2){
28597 for(var i = 0, finger; finger = touches[i]; i++){
28598 coords.push(finger.pageX, finger.pageY);
28601 var x = Math.pow(coords[0] - coords[2], 2);
28602 var y = Math.pow(coords[1] - coords[3], 2);
28604 this.startDistance = Math.sqrt(x + y);
28606 this.startScale = this.scale;
28608 this.pinching = true;
28609 this.dragable = false;
28613 onTouchMove : function(e)
28615 if(!this.pinching && !this.dragable){
28619 var touches = e.browserEvent.touches;
28626 this.onMouseMove(e);
28632 for(var i = 0, finger; finger = touches[i]; i++){
28633 coords.push(finger.pageX, finger.pageY);
28636 var x = Math.pow(coords[0] - coords[2], 2);
28637 var y = Math.pow(coords[1] - coords[3], 2);
28639 this.endDistance = Math.sqrt(x + y);
28641 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28643 if(!this.zoomable()){
28644 this.scale = this.startScale;
28652 onTouchEnd : function(e)
28654 this.pinching = false;
28655 this.dragable = false;
28659 process : function(file, crop)
28662 this.maskEl.mask(this.loadingText);
28665 this.xhr = new XMLHttpRequest();
28667 file.xhr = this.xhr;
28669 this.xhr.open(this.method, this.url, true);
28672 "Accept": "application/json",
28673 "Cache-Control": "no-cache",
28674 "X-Requested-With": "XMLHttpRequest"
28677 for (var headerName in headers) {
28678 var headerValue = headers[headerName];
28680 this.xhr.setRequestHeader(headerName, headerValue);
28686 this.xhr.onload = function()
28688 _this.xhrOnLoad(_this.xhr);
28691 this.xhr.onerror = function()
28693 _this.xhrOnError(_this.xhr);
28696 var formData = new FormData();
28698 formData.append('returnHTML', 'NO');
28701 formData.append('crop', crop);
28704 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28705 formData.append(this.paramName, file, file.name);
28708 if(typeof(file.filename) != 'undefined'){
28709 formData.append('filename', file.filename);
28712 if(typeof(file.mimetype) != 'undefined'){
28713 formData.append('mimetype', file.mimetype);
28716 if(this.fireEvent('arrange', this, formData) != false){
28717 this.xhr.send(formData);
28721 xhrOnLoad : function(xhr)
28724 this.maskEl.unmask();
28727 if (xhr.readyState !== 4) {
28728 this.fireEvent('exception', this, xhr);
28732 var response = Roo.decode(xhr.responseText);
28734 if(!response.success){
28735 this.fireEvent('exception', this, xhr);
28739 var response = Roo.decode(xhr.responseText);
28741 this.fireEvent('upload', this, response);
28745 xhrOnError : function()
28748 this.maskEl.unmask();
28751 Roo.log('xhr on error');
28753 var response = Roo.decode(xhr.responseText);
28759 prepare : function(file)
28762 this.maskEl.mask(this.loadingText);
28768 if(typeof(file) === 'string'){
28769 this.loadCanvas(file);
28773 if(!file || !this.urlAPI){
28778 this.cropType = file.type;
28782 if(this.fireEvent('prepare', this, this.file) != false){
28784 var reader = new FileReader();
28786 reader.onload = function (e) {
28787 if (e.target.error) {
28788 Roo.log(e.target.error);
28792 var buffer = e.target.result,
28793 dataView = new DataView(buffer),
28795 maxOffset = dataView.byteLength - 4,
28799 if (dataView.getUint16(0) === 0xffd8) {
28800 while (offset < maxOffset) {
28801 markerBytes = dataView.getUint16(offset);
28803 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28804 markerLength = dataView.getUint16(offset + 2) + 2;
28805 if (offset + markerLength > dataView.byteLength) {
28806 Roo.log('Invalid meta data: Invalid segment size.');
28810 if(markerBytes == 0xffe1){
28811 _this.parseExifData(
28818 offset += markerLength;
28828 var url = _this.urlAPI.createObjectURL(_this.file);
28830 _this.loadCanvas(url);
28835 reader.readAsArrayBuffer(this.file);
28841 parseExifData : function(dataView, offset, length)
28843 var tiffOffset = offset + 10,
28847 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28848 // No Exif data, might be XMP data instead
28852 // Check for the ASCII code for "Exif" (0x45786966):
28853 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28854 // No Exif data, might be XMP data instead
28857 if (tiffOffset + 8 > dataView.byteLength) {
28858 Roo.log('Invalid Exif data: Invalid segment size.');
28861 // Check for the two null bytes:
28862 if (dataView.getUint16(offset + 8) !== 0x0000) {
28863 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28866 // Check the byte alignment:
28867 switch (dataView.getUint16(tiffOffset)) {
28869 littleEndian = true;
28872 littleEndian = false;
28875 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28878 // Check for the TIFF tag marker (0x002A):
28879 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28880 Roo.log('Invalid Exif data: Missing TIFF marker.');
28883 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28884 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28886 this.parseExifTags(
28889 tiffOffset + dirOffset,
28894 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28899 if (dirOffset + 6 > dataView.byteLength) {
28900 Roo.log('Invalid Exif data: Invalid directory offset.');
28903 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28904 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28905 if (dirEndOffset + 4 > dataView.byteLength) {
28906 Roo.log('Invalid Exif data: Invalid directory size.');
28909 for (i = 0; i < tagsNumber; i += 1) {
28913 dirOffset + 2 + 12 * i, // tag offset
28917 // Return the offset to the next directory:
28918 return dataView.getUint32(dirEndOffset, littleEndian);
28921 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28923 var tag = dataView.getUint16(offset, littleEndian);
28925 this.exif[tag] = this.getExifValue(
28929 dataView.getUint16(offset + 2, littleEndian), // tag type
28930 dataView.getUint32(offset + 4, littleEndian), // tag length
28935 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28937 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28946 Roo.log('Invalid Exif data: Invalid tag type.');
28950 tagSize = tagType.size * length;
28951 // Determine if the value is contained in the dataOffset bytes,
28952 // or if the value at the dataOffset is a pointer to the actual data:
28953 dataOffset = tagSize > 4 ?
28954 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28955 if (dataOffset + tagSize > dataView.byteLength) {
28956 Roo.log('Invalid Exif data: Invalid data offset.');
28959 if (length === 1) {
28960 return tagType.getValue(dataView, dataOffset, littleEndian);
28963 for (i = 0; i < length; i += 1) {
28964 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28967 if (tagType.ascii) {
28969 // Concatenate the chars:
28970 for (i = 0; i < values.length; i += 1) {
28972 // Ignore the terminating NULL byte(s):
28973 if (c === '\u0000') {
28985 Roo.apply(Roo.bootstrap.UploadCropbox, {
28987 'Orientation': 0x0112
28991 1: 0, //'top-left',
28993 3: 180, //'bottom-right',
28994 // 4: 'bottom-left',
28996 6: 90, //'right-top',
28997 // 7: 'right-bottom',
28998 8: 270 //'left-bottom'
29002 // byte, 8-bit unsigned int:
29004 getValue: function (dataView, dataOffset) {
29005 return dataView.getUint8(dataOffset);
29009 // ascii, 8-bit byte:
29011 getValue: function (dataView, dataOffset) {
29012 return String.fromCharCode(dataView.getUint8(dataOffset));
29017 // short, 16 bit int:
29019 getValue: function (dataView, dataOffset, littleEndian) {
29020 return dataView.getUint16(dataOffset, littleEndian);
29024 // long, 32 bit int:
29026 getValue: function (dataView, dataOffset, littleEndian) {
29027 return dataView.getUint32(dataOffset, littleEndian);
29031 // rational = two long values, first is numerator, second is denominator:
29033 getValue: function (dataView, dataOffset, littleEndian) {
29034 return dataView.getUint32(dataOffset, littleEndian) /
29035 dataView.getUint32(dataOffset + 4, littleEndian);
29039 // slong, 32 bit signed int:
29041 getValue: function (dataView, dataOffset, littleEndian) {
29042 return dataView.getInt32(dataOffset, littleEndian);
29046 // srational, two slongs, first is numerator, second is denominator:
29048 getValue: function (dataView, dataOffset, littleEndian) {
29049 return dataView.getInt32(dataOffset, littleEndian) /
29050 dataView.getInt32(dataOffset + 4, littleEndian);
29060 cls : 'btn-group roo-upload-cropbox-rotate-left',
29061 action : 'rotate-left',
29065 cls : 'btn btn-default',
29066 html : '<i class="fa fa-undo"></i>'
29072 cls : 'btn-group roo-upload-cropbox-picture',
29073 action : 'picture',
29077 cls : 'btn btn-default',
29078 html : '<i class="fa fa-picture-o"></i>'
29084 cls : 'btn-group roo-upload-cropbox-rotate-right',
29085 action : 'rotate-right',
29089 cls : 'btn btn-default',
29090 html : '<i class="fa fa-repeat"></i>'
29098 cls : 'btn-group roo-upload-cropbox-rotate-left',
29099 action : 'rotate-left',
29103 cls : 'btn btn-default',
29104 html : '<i class="fa fa-undo"></i>'
29110 cls : 'btn-group roo-upload-cropbox-download',
29111 action : 'download',
29115 cls : 'btn btn-default',
29116 html : '<i class="fa fa-download"></i>'
29122 cls : 'btn-group roo-upload-cropbox-crop',
29127 cls : 'btn btn-default',
29128 html : '<i class="fa fa-crop"></i>'
29134 cls : 'btn-group roo-upload-cropbox-trash',
29139 cls : 'btn btn-default',
29140 html : '<i class="fa fa-trash"></i>'
29146 cls : 'btn-group roo-upload-cropbox-rotate-right',
29147 action : 'rotate-right',
29151 cls : 'btn btn-default',
29152 html : '<i class="fa fa-repeat"></i>'
29160 cls : 'btn-group roo-upload-cropbox-rotate-left',
29161 action : 'rotate-left',
29165 cls : 'btn btn-default',
29166 html : '<i class="fa fa-undo"></i>'
29172 cls : 'btn-group roo-upload-cropbox-rotate-right',
29173 action : 'rotate-right',
29177 cls : 'btn btn-default',
29178 html : '<i class="fa fa-repeat"></i>'
29191 * @class Roo.bootstrap.DocumentManager
29192 * @extends Roo.bootstrap.Component
29193 * Bootstrap DocumentManager class
29194 * @cfg {String} paramName default 'imageUpload'
29195 * @cfg {String} toolTipName default 'filename'
29196 * @cfg {String} method default POST
29197 * @cfg {String} url action url
29198 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29199 * @cfg {Boolean} multiple multiple upload default true
29200 * @cfg {Number} thumbSize default 300
29201 * @cfg {String} fieldLabel
29202 * @cfg {Number} labelWidth default 4
29203 * @cfg {String} labelAlign (left|top) default left
29204 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29205 * @cfg {Number} labellg set the width of label (1-12)
29206 * @cfg {Number} labelmd set the width of label (1-12)
29207 * @cfg {Number} labelsm set the width of label (1-12)
29208 * @cfg {Number} labelxs set the width of label (1-12)
29211 * Create a new DocumentManager
29212 * @param {Object} config The config object
29215 Roo.bootstrap.DocumentManager = function(config){
29216 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29219 this.delegates = [];
29224 * Fire when initial the DocumentManager
29225 * @param {Roo.bootstrap.DocumentManager} this
29230 * inspect selected file
29231 * @param {Roo.bootstrap.DocumentManager} this
29232 * @param {File} file
29237 * Fire when xhr load exception
29238 * @param {Roo.bootstrap.DocumentManager} this
29239 * @param {XMLHttpRequest} xhr
29241 "exception" : true,
29243 * @event afterupload
29244 * Fire when xhr load exception
29245 * @param {Roo.bootstrap.DocumentManager} this
29246 * @param {XMLHttpRequest} xhr
29248 "afterupload" : true,
29251 * prepare the form data
29252 * @param {Roo.bootstrap.DocumentManager} this
29253 * @param {Object} formData
29258 * Fire when remove the file
29259 * @param {Roo.bootstrap.DocumentManager} this
29260 * @param {Object} file
29265 * Fire after refresh the file
29266 * @param {Roo.bootstrap.DocumentManager} this
29271 * Fire after click the image
29272 * @param {Roo.bootstrap.DocumentManager} this
29273 * @param {Object} file
29278 * Fire when upload a image and editable set to true
29279 * @param {Roo.bootstrap.DocumentManager} this
29280 * @param {Object} file
29284 * @event beforeselectfile
29285 * Fire before select file
29286 * @param {Roo.bootstrap.DocumentManager} this
29288 "beforeselectfile" : true,
29291 * Fire before process file
29292 * @param {Roo.bootstrap.DocumentManager} this
29293 * @param {Object} file
29297 * @event previewrendered
29298 * Fire when preview rendered
29299 * @param {Roo.bootstrap.DocumentManager} this
29300 * @param {Object} file
29302 "previewrendered" : true,
29305 "previewResize" : true
29310 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29319 paramName : 'imageUpload',
29320 toolTipName : 'filename',
29323 labelAlign : 'left',
29333 getAutoCreate : function()
29335 var managerWidget = {
29337 cls : 'roo-document-manager',
29341 cls : 'roo-document-manager-selector',
29346 cls : 'roo-document-manager-uploader',
29350 cls : 'roo-document-manager-upload-btn',
29351 html : '<i class="fa fa-plus"></i>'
29362 cls : 'column col-md-12',
29367 if(this.fieldLabel.length){
29372 cls : 'column col-md-12',
29373 html : this.fieldLabel
29377 cls : 'column col-md-12',
29382 if(this.labelAlign == 'left'){
29387 html : this.fieldLabel
29396 if(this.labelWidth > 12){
29397 content[0].style = "width: " + this.labelWidth + 'px';
29400 if(this.labelWidth < 13 && this.labelmd == 0){
29401 this.labelmd = this.labelWidth;
29404 if(this.labellg > 0){
29405 content[0].cls += ' col-lg-' + this.labellg;
29406 content[1].cls += ' col-lg-' + (12 - this.labellg);
29409 if(this.labelmd > 0){
29410 content[0].cls += ' col-md-' + this.labelmd;
29411 content[1].cls += ' col-md-' + (12 - this.labelmd);
29414 if(this.labelsm > 0){
29415 content[0].cls += ' col-sm-' + this.labelsm;
29416 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29419 if(this.labelxs > 0){
29420 content[0].cls += ' col-xs-' + this.labelxs;
29421 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29429 cls : 'row clearfix',
29437 initEvents : function()
29439 this.managerEl = this.el.select('.roo-document-manager', true).first();
29440 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29442 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29443 this.selectorEl.hide();
29446 this.selectorEl.attr('multiple', 'multiple');
29449 this.selectorEl.on('change', this.onFileSelected, this);
29451 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29452 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29454 this.uploader.on('click', this.onUploaderClick, this);
29456 this.renderProgressDialog();
29460 window.addEventListener("resize", function() { _this.refresh(); } );
29462 this.fireEvent('initial', this);
29465 renderProgressDialog : function()
29469 this.progressDialog = new Roo.bootstrap.Modal({
29470 cls : 'roo-document-manager-progress-dialog',
29471 allow_close : false,
29482 btnclick : function() {
29483 _this.uploadCancel();
29489 this.progressDialog.render(Roo.get(document.body));
29491 this.progress = new Roo.bootstrap.Progress({
29492 cls : 'roo-document-manager-progress',
29497 this.progress.render(this.progressDialog.getChildContainer());
29499 this.progressBar = new Roo.bootstrap.ProgressBar({
29500 cls : 'roo-document-manager-progress-bar',
29503 aria_valuemax : 12,
29507 this.progressBar.render(this.progress.getChildContainer());
29510 onUploaderClick : function(e)
29512 e.preventDefault();
29514 if(this.fireEvent('beforeselectfile', this) != false){
29515 this.selectorEl.dom.click();
29520 onFileSelected : function(e)
29522 e.preventDefault();
29524 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29528 Roo.each(this.selectorEl.dom.files, function(file){
29529 if(this.fireEvent('inspect', this, file) != false){
29530 this.files.push(file);
29540 this.selectorEl.dom.value = '';
29542 if(!this.files || !this.files.length){
29546 if(this.boxes > 0 && this.files.length > this.boxes){
29547 this.files = this.files.slice(0, this.boxes);
29550 this.uploader.show();
29552 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29553 this.uploader.hide();
29562 Roo.each(this.files, function(file){
29564 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29565 var f = this.renderPreview(file);
29570 if(file.type.indexOf('image') != -1){
29571 this.delegates.push(
29573 _this.process(file);
29574 }).createDelegate(this)
29582 _this.process(file);
29583 }).createDelegate(this)
29588 this.files = files;
29590 this.delegates = this.delegates.concat(docs);
29592 if(!this.delegates.length){
29597 this.progressBar.aria_valuemax = this.delegates.length;
29604 arrange : function()
29606 if(!this.delegates.length){
29607 this.progressDialog.hide();
29612 var delegate = this.delegates.shift();
29614 this.progressDialog.show();
29616 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29618 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29623 refresh : function()
29625 this.uploader.show();
29627 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29628 this.uploader.hide();
29631 Roo.isTouch ? this.closable(false) : this.closable(true);
29633 this.fireEvent('refresh', this);
29636 onRemove : function(e, el, o)
29638 e.preventDefault();
29640 this.fireEvent('remove', this, o);
29644 remove : function(o)
29648 Roo.each(this.files, function(file){
29649 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29658 this.files = files;
29665 Roo.each(this.files, function(file){
29670 file.target.remove();
29679 onClick : function(e, el, o)
29681 e.preventDefault();
29683 this.fireEvent('click', this, o);
29687 closable : function(closable)
29689 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29691 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29703 xhrOnLoad : function(xhr)
29705 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29709 if (xhr.readyState !== 4) {
29711 this.fireEvent('exception', this, xhr);
29715 var response = Roo.decode(xhr.responseText);
29717 if(!response.success){
29719 this.fireEvent('exception', this, xhr);
29723 var file = this.renderPreview(response.data);
29725 this.files.push(file);
29729 this.fireEvent('afterupload', this, xhr);
29733 xhrOnError : function(xhr)
29735 Roo.log('xhr on error');
29737 var response = Roo.decode(xhr.responseText);
29744 process : function(file)
29746 if(this.fireEvent('process', this, file) !== false){
29747 if(this.editable && file.type.indexOf('image') != -1){
29748 this.fireEvent('edit', this, file);
29752 this.uploadStart(file, false);
29759 uploadStart : function(file, crop)
29761 this.xhr = new XMLHttpRequest();
29763 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29768 file.xhr = this.xhr;
29770 this.managerEl.createChild({
29772 cls : 'roo-document-manager-loading',
29776 tooltip : file.name,
29777 cls : 'roo-document-manager-thumb',
29778 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29784 this.xhr.open(this.method, this.url, true);
29787 "Accept": "application/json",
29788 "Cache-Control": "no-cache",
29789 "X-Requested-With": "XMLHttpRequest"
29792 for (var headerName in headers) {
29793 var headerValue = headers[headerName];
29795 this.xhr.setRequestHeader(headerName, headerValue);
29801 this.xhr.onload = function()
29803 _this.xhrOnLoad(_this.xhr);
29806 this.xhr.onerror = function()
29808 _this.xhrOnError(_this.xhr);
29811 var formData = new FormData();
29813 formData.append('returnHTML', 'NO');
29816 formData.append('crop', crop);
29819 formData.append(this.paramName, file, file.name);
29826 if(this.fireEvent('prepare', this, formData, options) != false){
29828 if(options.manually){
29832 this.xhr.send(formData);
29836 this.uploadCancel();
29839 uploadCancel : function()
29845 this.delegates = [];
29847 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29854 renderPreview : function(file)
29856 if(typeof(file.target) != 'undefined' && file.target){
29860 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29862 var previewEl = this.managerEl.createChild({
29864 cls : 'roo-document-manager-preview',
29868 tooltip : file[this.toolTipName],
29869 cls : 'roo-document-manager-thumb',
29870 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29875 html : '<i class="fa fa-times-circle"></i>'
29880 var close = previewEl.select('button.close', true).first();
29882 close.on('click', this.onRemove, this, file);
29884 file.target = previewEl;
29886 var image = previewEl.select('img', true).first();
29890 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29892 image.on('click', this.onClick, this, file);
29894 this.fireEvent('previewrendered', this, file);
29900 onPreviewLoad : function(file, image)
29902 if(typeof(file.target) == 'undefined' || !file.target){
29906 var width = image.dom.naturalWidth || image.dom.width;
29907 var height = image.dom.naturalHeight || image.dom.height;
29909 if(!this.previewResize) {
29913 if(width > height){
29914 file.target.addClass('wide');
29918 file.target.addClass('tall');
29923 uploadFromSource : function(file, crop)
29925 this.xhr = new XMLHttpRequest();
29927 this.managerEl.createChild({
29929 cls : 'roo-document-manager-loading',
29933 tooltip : file.name,
29934 cls : 'roo-document-manager-thumb',
29935 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29941 this.xhr.open(this.method, this.url, true);
29944 "Accept": "application/json",
29945 "Cache-Control": "no-cache",
29946 "X-Requested-With": "XMLHttpRequest"
29949 for (var headerName in headers) {
29950 var headerValue = headers[headerName];
29952 this.xhr.setRequestHeader(headerName, headerValue);
29958 this.xhr.onload = function()
29960 _this.xhrOnLoad(_this.xhr);
29963 this.xhr.onerror = function()
29965 _this.xhrOnError(_this.xhr);
29968 var formData = new FormData();
29970 formData.append('returnHTML', 'NO');
29972 formData.append('crop', crop);
29974 if(typeof(file.filename) != 'undefined'){
29975 formData.append('filename', file.filename);
29978 if(typeof(file.mimetype) != 'undefined'){
29979 formData.append('mimetype', file.mimetype);
29984 if(this.fireEvent('prepare', this, formData) != false){
29985 this.xhr.send(formData);
29995 * @class Roo.bootstrap.DocumentViewer
29996 * @extends Roo.bootstrap.Component
29997 * Bootstrap DocumentViewer class
29998 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29999 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
30002 * Create a new DocumentViewer
30003 * @param {Object} config The config object
30006 Roo.bootstrap.DocumentViewer = function(config){
30007 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
30012 * Fire after initEvent
30013 * @param {Roo.bootstrap.DocumentViewer} this
30019 * @param {Roo.bootstrap.DocumentViewer} this
30024 * Fire after download button
30025 * @param {Roo.bootstrap.DocumentViewer} this
30030 * Fire after trash button
30031 * @param {Roo.bootstrap.DocumentViewer} this
30038 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
30040 showDownload : true,
30044 getAutoCreate : function()
30048 cls : 'roo-document-viewer',
30052 cls : 'roo-document-viewer-body',
30056 cls : 'roo-document-viewer-thumb',
30060 cls : 'roo-document-viewer-image'
30068 cls : 'roo-document-viewer-footer',
30071 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30075 cls : 'btn-group roo-document-viewer-download',
30079 cls : 'btn btn-default',
30080 html : '<i class="fa fa-download"></i>'
30086 cls : 'btn-group roo-document-viewer-trash',
30090 cls : 'btn btn-default',
30091 html : '<i class="fa fa-trash"></i>'
30104 initEvents : function()
30106 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30107 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30109 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30110 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30112 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30113 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30115 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30116 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30118 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30119 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30121 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30122 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30124 this.bodyEl.on('click', this.onClick, this);
30125 this.downloadBtn.on('click', this.onDownload, this);
30126 this.trashBtn.on('click', this.onTrash, this);
30128 this.downloadBtn.hide();
30129 this.trashBtn.hide();
30131 if(this.showDownload){
30132 this.downloadBtn.show();
30135 if(this.showTrash){
30136 this.trashBtn.show();
30139 if(!this.showDownload && !this.showTrash) {
30140 this.footerEl.hide();
30145 initial : function()
30147 this.fireEvent('initial', this);
30151 onClick : function(e)
30153 e.preventDefault();
30155 this.fireEvent('click', this);
30158 onDownload : function(e)
30160 e.preventDefault();
30162 this.fireEvent('download', this);
30165 onTrash : function(e)
30167 e.preventDefault();
30169 this.fireEvent('trash', this);
30181 * @class Roo.bootstrap.NavProgressBar
30182 * @extends Roo.bootstrap.Component
30183 * Bootstrap NavProgressBar class
30186 * Create a new nav progress bar
30187 * @param {Object} config The config object
30190 Roo.bootstrap.NavProgressBar = function(config){
30191 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30193 this.bullets = this.bullets || [];
30195 // Roo.bootstrap.NavProgressBar.register(this);
30199 * Fires when the active item changes
30200 * @param {Roo.bootstrap.NavProgressBar} this
30201 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30202 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30209 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30214 getAutoCreate : function()
30216 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30220 cls : 'roo-navigation-bar-group',
30224 cls : 'roo-navigation-top-bar'
30228 cls : 'roo-navigation-bullets-bar',
30232 cls : 'roo-navigation-bar'
30239 cls : 'roo-navigation-bottom-bar'
30249 initEvents: function()
30254 onRender : function(ct, position)
30256 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30258 if(this.bullets.length){
30259 Roo.each(this.bullets, function(b){
30268 addItem : function(cfg)
30270 var item = new Roo.bootstrap.NavProgressItem(cfg);
30272 item.parentId = this.id;
30273 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30276 var top = new Roo.bootstrap.Element({
30278 cls : 'roo-navigation-bar-text'
30281 var bottom = new Roo.bootstrap.Element({
30283 cls : 'roo-navigation-bar-text'
30286 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30287 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30289 var topText = new Roo.bootstrap.Element({
30291 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30294 var bottomText = new Roo.bootstrap.Element({
30296 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30299 topText.onRender(top.el, null);
30300 bottomText.onRender(bottom.el, null);
30303 item.bottomEl = bottom;
30306 this.barItems.push(item);
30311 getActive : function()
30313 var active = false;
30315 Roo.each(this.barItems, function(v){
30317 if (!v.isActive()) {
30329 setActiveItem : function(item)
30333 Roo.each(this.barItems, function(v){
30334 if (v.rid == item.rid) {
30338 if (v.isActive()) {
30339 v.setActive(false);
30344 item.setActive(true);
30346 this.fireEvent('changed', this, item, prev);
30349 getBarItem: function(rid)
30353 Roo.each(this.barItems, function(e) {
30354 if (e.rid != rid) {
30365 indexOfItem : function(item)
30369 Roo.each(this.barItems, function(v, i){
30371 if (v.rid != item.rid) {
30382 setActiveNext : function()
30384 var i = this.indexOfItem(this.getActive());
30386 if (i > this.barItems.length) {
30390 this.setActiveItem(this.barItems[i+1]);
30393 setActivePrev : function()
30395 var i = this.indexOfItem(this.getActive());
30401 this.setActiveItem(this.barItems[i-1]);
30404 format : function()
30406 if(!this.barItems.length){
30410 var width = 100 / this.barItems.length;
30412 Roo.each(this.barItems, function(i){
30413 i.el.setStyle('width', width + '%');
30414 i.topEl.el.setStyle('width', width + '%');
30415 i.bottomEl.el.setStyle('width', width + '%');
30424 * Nav Progress Item
30429 * @class Roo.bootstrap.NavProgressItem
30430 * @extends Roo.bootstrap.Component
30431 * Bootstrap NavProgressItem class
30432 * @cfg {String} rid the reference id
30433 * @cfg {Boolean} active (true|false) Is item active default false
30434 * @cfg {Boolean} disabled (true|false) Is item active default false
30435 * @cfg {String} html
30436 * @cfg {String} position (top|bottom) text position default bottom
30437 * @cfg {String} icon show icon instead of number
30440 * Create a new NavProgressItem
30441 * @param {Object} config The config object
30443 Roo.bootstrap.NavProgressItem = function(config){
30444 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30449 * The raw click event for the entire grid.
30450 * @param {Roo.bootstrap.NavProgressItem} this
30451 * @param {Roo.EventObject} e
30458 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30464 position : 'bottom',
30467 getAutoCreate : function()
30469 var iconCls = 'roo-navigation-bar-item-icon';
30471 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30475 cls: 'roo-navigation-bar-item',
30485 cfg.cls += ' active';
30488 cfg.cls += ' disabled';
30494 disable : function()
30496 this.setDisabled(true);
30499 enable : function()
30501 this.setDisabled(false);
30504 initEvents: function()
30506 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30508 this.iconEl.on('click', this.onClick, this);
30511 onClick : function(e)
30513 e.preventDefault();
30519 if(this.fireEvent('click', this, e) === false){
30523 this.parent().setActiveItem(this);
30526 isActive: function ()
30528 return this.active;
30531 setActive : function(state)
30533 if(this.active == state){
30537 this.active = state;
30540 this.el.addClass('active');
30544 this.el.removeClass('active');
30549 setDisabled : function(state)
30551 if(this.disabled == state){
30555 this.disabled = state;
30558 this.el.addClass('disabled');
30562 this.el.removeClass('disabled');
30565 tooltipEl : function()
30567 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30580 * @class Roo.bootstrap.FieldLabel
30581 * @extends Roo.bootstrap.Component
30582 * Bootstrap FieldLabel class
30583 * @cfg {String} html contents of the element
30584 * @cfg {String} tag tag of the element default label
30585 * @cfg {String} cls class of the element
30586 * @cfg {String} target label target
30587 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30588 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30589 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30590 * @cfg {String} iconTooltip default "This field is required"
30591 * @cfg {String} indicatorpos (left|right) default left
30594 * Create a new FieldLabel
30595 * @param {Object} config The config object
30598 Roo.bootstrap.FieldLabel = function(config){
30599 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30604 * Fires after the field has been marked as invalid.
30605 * @param {Roo.form.FieldLabel} this
30606 * @param {String} msg The validation message
30611 * Fires after the field has been validated with no errors.
30612 * @param {Roo.form.FieldLabel} this
30618 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30625 invalidClass : 'has-warning',
30626 validClass : 'has-success',
30627 iconTooltip : 'This field is required',
30628 indicatorpos : 'left',
30630 getAutoCreate : function(){
30633 if (!this.allowBlank) {
30639 cls : 'roo-bootstrap-field-label ' + this.cls,
30644 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30645 tooltip : this.iconTooltip
30654 if(this.indicatorpos == 'right'){
30657 cls : 'roo-bootstrap-field-label ' + this.cls,
30666 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30667 tooltip : this.iconTooltip
30676 initEvents: function()
30678 Roo.bootstrap.Element.superclass.initEvents.call(this);
30680 this.indicator = this.indicatorEl();
30682 if(this.indicator){
30683 this.indicator.removeClass('visible');
30684 this.indicator.addClass('invisible');
30687 Roo.bootstrap.FieldLabel.register(this);
30690 indicatorEl : function()
30692 var indicator = this.el.select('i.roo-required-indicator',true).first();
30703 * Mark this field as valid
30705 markValid : function()
30707 if(this.indicator){
30708 this.indicator.removeClass('visible');
30709 this.indicator.addClass('invisible');
30711 if (Roo.bootstrap.version == 3) {
30712 this.el.removeClass(this.invalidClass);
30713 this.el.addClass(this.validClass);
30715 this.el.removeClass('is-invalid');
30716 this.el.addClass('is-valid');
30720 this.fireEvent('valid', this);
30724 * Mark this field as invalid
30725 * @param {String} msg The validation message
30727 markInvalid : function(msg)
30729 if(this.indicator){
30730 this.indicator.removeClass('invisible');
30731 this.indicator.addClass('visible');
30733 if (Roo.bootstrap.version == 3) {
30734 this.el.removeClass(this.validClass);
30735 this.el.addClass(this.invalidClass);
30737 this.el.removeClass('is-valid');
30738 this.el.addClass('is-invalid');
30742 this.fireEvent('invalid', this, msg);
30748 Roo.apply(Roo.bootstrap.FieldLabel, {
30753 * register a FieldLabel Group
30754 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30756 register : function(label)
30758 if(this.groups.hasOwnProperty(label.target)){
30762 this.groups[label.target] = label;
30766 * fetch a FieldLabel Group based on the target
30767 * @param {string} target
30768 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30770 get: function(target) {
30771 if (typeof(this.groups[target]) == 'undefined') {
30775 return this.groups[target] ;
30784 * page DateSplitField.
30790 * @class Roo.bootstrap.DateSplitField
30791 * @extends Roo.bootstrap.Component
30792 * Bootstrap DateSplitField class
30793 * @cfg {string} fieldLabel - the label associated
30794 * @cfg {Number} labelWidth set the width of label (0-12)
30795 * @cfg {String} labelAlign (top|left)
30796 * @cfg {Boolean} dayAllowBlank (true|false) default false
30797 * @cfg {Boolean} monthAllowBlank (true|false) default false
30798 * @cfg {Boolean} yearAllowBlank (true|false) default false
30799 * @cfg {string} dayPlaceholder
30800 * @cfg {string} monthPlaceholder
30801 * @cfg {string} yearPlaceholder
30802 * @cfg {string} dayFormat default 'd'
30803 * @cfg {string} monthFormat default 'm'
30804 * @cfg {string} yearFormat default 'Y'
30805 * @cfg {Number} labellg set the width of label (1-12)
30806 * @cfg {Number} labelmd set the width of label (1-12)
30807 * @cfg {Number} labelsm set the width of label (1-12)
30808 * @cfg {Number} labelxs set the width of label (1-12)
30812 * Create a new DateSplitField
30813 * @param {Object} config The config object
30816 Roo.bootstrap.DateSplitField = function(config){
30817 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30823 * getting the data of years
30824 * @param {Roo.bootstrap.DateSplitField} this
30825 * @param {Object} years
30830 * getting the data of days
30831 * @param {Roo.bootstrap.DateSplitField} this
30832 * @param {Object} days
30837 * Fires after the field has been marked as invalid.
30838 * @param {Roo.form.Field} this
30839 * @param {String} msg The validation message
30844 * Fires after the field has been validated with no errors.
30845 * @param {Roo.form.Field} this
30851 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30854 labelAlign : 'top',
30856 dayAllowBlank : false,
30857 monthAllowBlank : false,
30858 yearAllowBlank : false,
30859 dayPlaceholder : '',
30860 monthPlaceholder : '',
30861 yearPlaceholder : '',
30865 isFormField : true,
30871 getAutoCreate : function()
30875 cls : 'row roo-date-split-field-group',
30880 cls : 'form-hidden-field roo-date-split-field-group-value',
30886 var labelCls = 'col-md-12';
30887 var contentCls = 'col-md-4';
30889 if(this.fieldLabel){
30893 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30897 html : this.fieldLabel
30902 if(this.labelAlign == 'left'){
30904 if(this.labelWidth > 12){
30905 label.style = "width: " + this.labelWidth + 'px';
30908 if(this.labelWidth < 13 && this.labelmd == 0){
30909 this.labelmd = this.labelWidth;
30912 if(this.labellg > 0){
30913 labelCls = ' col-lg-' + this.labellg;
30914 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30917 if(this.labelmd > 0){
30918 labelCls = ' col-md-' + this.labelmd;
30919 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30922 if(this.labelsm > 0){
30923 labelCls = ' col-sm-' + this.labelsm;
30924 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30927 if(this.labelxs > 0){
30928 labelCls = ' col-xs-' + this.labelxs;
30929 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30933 label.cls += ' ' + labelCls;
30935 cfg.cn.push(label);
30938 Roo.each(['day', 'month', 'year'], function(t){
30941 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30948 inputEl: function ()
30950 return this.el.select('.roo-date-split-field-group-value', true).first();
30953 onRender : function(ct, position)
30957 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30959 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30961 this.dayField = new Roo.bootstrap.ComboBox({
30962 allowBlank : this.dayAllowBlank,
30963 alwaysQuery : true,
30964 displayField : 'value',
30967 forceSelection : true,
30969 placeholder : this.dayPlaceholder,
30970 selectOnFocus : true,
30971 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30972 triggerAction : 'all',
30974 valueField : 'value',
30975 store : new Roo.data.SimpleStore({
30976 data : (function() {
30978 _this.fireEvent('days', _this, days);
30981 fields : [ 'value' ]
30984 select : function (_self, record, index)
30986 _this.setValue(_this.getValue());
30991 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30993 this.monthField = new Roo.bootstrap.MonthField({
30994 after : '<i class=\"fa fa-calendar\"></i>',
30995 allowBlank : this.monthAllowBlank,
30996 placeholder : this.monthPlaceholder,
30999 render : function (_self)
31001 this.el.select('span.input-group-addon', true).first().on('click', function(e){
31002 e.preventDefault();
31006 select : function (_self, oldvalue, newvalue)
31008 _this.setValue(_this.getValue());
31013 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
31015 this.yearField = new Roo.bootstrap.ComboBox({
31016 allowBlank : this.yearAllowBlank,
31017 alwaysQuery : true,
31018 displayField : 'value',
31021 forceSelection : true,
31023 placeholder : this.yearPlaceholder,
31024 selectOnFocus : true,
31025 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
31026 triggerAction : 'all',
31028 valueField : 'value',
31029 store : new Roo.data.SimpleStore({
31030 data : (function() {
31032 _this.fireEvent('years', _this, years);
31035 fields : [ 'value' ]
31038 select : function (_self, record, index)
31040 _this.setValue(_this.getValue());
31045 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
31048 setValue : function(v, format)
31050 this.inputEl.dom.value = v;
31052 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
31054 var d = Date.parseDate(v, f);
31061 this.setDay(d.format(this.dayFormat));
31062 this.setMonth(d.format(this.monthFormat));
31063 this.setYear(d.format(this.yearFormat));
31070 setDay : function(v)
31072 this.dayField.setValue(v);
31073 this.inputEl.dom.value = this.getValue();
31078 setMonth : function(v)
31080 this.monthField.setValue(v, true);
31081 this.inputEl.dom.value = this.getValue();
31086 setYear : function(v)
31088 this.yearField.setValue(v);
31089 this.inputEl.dom.value = this.getValue();
31094 getDay : function()
31096 return this.dayField.getValue();
31099 getMonth : function()
31101 return this.monthField.getValue();
31104 getYear : function()
31106 return this.yearField.getValue();
31109 getValue : function()
31111 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31113 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31123 this.inputEl.dom.value = '';
31128 validate : function()
31130 var d = this.dayField.validate();
31131 var m = this.monthField.validate();
31132 var y = this.yearField.validate();
31137 (!this.dayAllowBlank && !d) ||
31138 (!this.monthAllowBlank && !m) ||
31139 (!this.yearAllowBlank && !y)
31144 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31153 this.markInvalid();
31158 markValid : function()
31161 var label = this.el.select('label', true).first();
31162 var icon = this.el.select('i.fa-star', true).first();
31168 this.fireEvent('valid', this);
31172 * Mark this field as invalid
31173 * @param {String} msg The validation message
31175 markInvalid : function(msg)
31178 var label = this.el.select('label', true).first();
31179 var icon = this.el.select('i.fa-star', true).first();
31181 if(label && !icon){
31182 this.el.select('.roo-date-split-field-label', true).createChild({
31184 cls : 'text-danger fa fa-lg fa-star',
31185 tooltip : 'This field is required',
31186 style : 'margin-right:5px;'
31190 this.fireEvent('invalid', this, msg);
31193 clearInvalid : function()
31195 var label = this.el.select('label', true).first();
31196 var icon = this.el.select('i.fa-star', true).first();
31202 this.fireEvent('valid', this);
31205 getName: function()
31215 * http://masonry.desandro.com
31217 * The idea is to render all the bricks based on vertical width...
31219 * The original code extends 'outlayer' - we might need to use that....
31225 * @class Roo.bootstrap.LayoutMasonry
31226 * @extends Roo.bootstrap.Component
31227 * Bootstrap Layout Masonry class
31230 * Create a new Element
31231 * @param {Object} config The config object
31234 Roo.bootstrap.LayoutMasonry = function(config){
31236 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31240 Roo.bootstrap.LayoutMasonry.register(this);
31246 * Fire after layout the items
31247 * @param {Roo.bootstrap.LayoutMasonry} this
31248 * @param {Roo.EventObject} e
31255 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31258 * @cfg {Boolean} isLayoutInstant = no animation?
31260 isLayoutInstant : false, // needed?
31263 * @cfg {Number} boxWidth width of the columns
31268 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31273 * @cfg {Number} padWidth padding below box..
31278 * @cfg {Number} gutter gutter width..
31283 * @cfg {Number} maxCols maximum number of columns
31289 * @cfg {Boolean} isAutoInitial defalut true
31291 isAutoInitial : true,
31296 * @cfg {Boolean} isHorizontal defalut false
31298 isHorizontal : false,
31300 currentSize : null,
31306 bricks: null, //CompositeElement
31310 _isLayoutInited : false,
31312 // isAlternative : false, // only use for vertical layout...
31315 * @cfg {Number} alternativePadWidth padding below box..
31317 alternativePadWidth : 50,
31319 selectedBrick : [],
31321 getAutoCreate : function(){
31323 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31327 cls: 'blog-masonary-wrapper ' + this.cls,
31329 cls : 'mas-boxes masonary'
31336 getChildContainer: function( )
31338 if (this.boxesEl) {
31339 return this.boxesEl;
31342 this.boxesEl = this.el.select('.mas-boxes').first();
31344 return this.boxesEl;
31348 initEvents : function()
31352 if(this.isAutoInitial){
31353 Roo.log('hook children rendered');
31354 this.on('childrenrendered', function() {
31355 Roo.log('children rendered');
31361 initial : function()
31363 this.selectedBrick = [];
31365 this.currentSize = this.el.getBox(true);
31367 Roo.EventManager.onWindowResize(this.resize, this);
31369 if(!this.isAutoInitial){
31377 //this.layout.defer(500,this);
31381 resize : function()
31383 var cs = this.el.getBox(true);
31386 this.currentSize.width == cs.width &&
31387 this.currentSize.x == cs.x &&
31388 this.currentSize.height == cs.height &&
31389 this.currentSize.y == cs.y
31391 Roo.log("no change in with or X or Y");
31395 this.currentSize = cs;
31401 layout : function()
31403 this._resetLayout();
31405 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31407 this.layoutItems( isInstant );
31409 this._isLayoutInited = true;
31411 this.fireEvent('layout', this);
31415 _resetLayout : function()
31417 if(this.isHorizontal){
31418 this.horizontalMeasureColumns();
31422 this.verticalMeasureColumns();
31426 verticalMeasureColumns : function()
31428 this.getContainerWidth();
31430 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31431 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31435 var boxWidth = this.boxWidth + this.padWidth;
31437 if(this.containerWidth < this.boxWidth){
31438 boxWidth = this.containerWidth
31441 var containerWidth = this.containerWidth;
31443 var cols = Math.floor(containerWidth / boxWidth);
31445 this.cols = Math.max( cols, 1 );
31447 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31449 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31451 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31453 this.colWidth = boxWidth + avail - this.padWidth;
31455 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31456 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31459 horizontalMeasureColumns : function()
31461 this.getContainerWidth();
31463 var boxWidth = this.boxWidth;
31465 if(this.containerWidth < boxWidth){
31466 boxWidth = this.containerWidth;
31469 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31471 this.el.setHeight(boxWidth);
31475 getContainerWidth : function()
31477 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31480 layoutItems : function( isInstant )
31482 Roo.log(this.bricks);
31484 var items = Roo.apply([], this.bricks);
31486 if(this.isHorizontal){
31487 this._horizontalLayoutItems( items , isInstant );
31491 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31492 // this._verticalAlternativeLayoutItems( items , isInstant );
31496 this._verticalLayoutItems( items , isInstant );
31500 _verticalLayoutItems : function ( items , isInstant)
31502 if ( !items || !items.length ) {
31507 ['xs', 'xs', 'xs', 'tall'],
31508 ['xs', 'xs', 'tall'],
31509 ['xs', 'xs', 'sm'],
31510 ['xs', 'xs', 'xs'],
31516 ['sm', 'xs', 'xs'],
31520 ['tall', 'xs', 'xs', 'xs'],
31521 ['tall', 'xs', 'xs'],
31533 Roo.each(items, function(item, k){
31535 switch (item.size) {
31536 // these layouts take up a full box,
31547 boxes.push([item]);
31570 var filterPattern = function(box, length)
31578 var pattern = box.slice(0, length);
31582 Roo.each(pattern, function(i){
31583 format.push(i.size);
31586 Roo.each(standard, function(s){
31588 if(String(s) != String(format)){
31597 if(!match && length == 1){
31602 filterPattern(box, length - 1);
31606 queue.push(pattern);
31608 box = box.slice(length, box.length);
31610 filterPattern(box, 4);
31616 Roo.each(boxes, function(box, k){
31622 if(box.length == 1){
31627 filterPattern(box, 4);
31631 this._processVerticalLayoutQueue( queue, isInstant );
31635 // _verticalAlternativeLayoutItems : function( items , isInstant )
31637 // if ( !items || !items.length ) {
31641 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31645 _horizontalLayoutItems : function ( items , isInstant)
31647 if ( !items || !items.length || items.length < 3) {
31653 var eItems = items.slice(0, 3);
31655 items = items.slice(3, items.length);
31658 ['xs', 'xs', 'xs', 'wide'],
31659 ['xs', 'xs', 'wide'],
31660 ['xs', 'xs', 'sm'],
31661 ['xs', 'xs', 'xs'],
31667 ['sm', 'xs', 'xs'],
31671 ['wide', 'xs', 'xs', 'xs'],
31672 ['wide', 'xs', 'xs'],
31685 Roo.each(items, function(item, k){
31687 switch (item.size) {
31698 boxes.push([item]);
31722 var filterPattern = function(box, length)
31730 var pattern = box.slice(0, length);
31734 Roo.each(pattern, function(i){
31735 format.push(i.size);
31738 Roo.each(standard, function(s){
31740 if(String(s) != String(format)){
31749 if(!match && length == 1){
31754 filterPattern(box, length - 1);
31758 queue.push(pattern);
31760 box = box.slice(length, box.length);
31762 filterPattern(box, 4);
31768 Roo.each(boxes, function(box, k){
31774 if(box.length == 1){
31779 filterPattern(box, 4);
31786 var pos = this.el.getBox(true);
31790 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31792 var hit_end = false;
31794 Roo.each(queue, function(box){
31798 Roo.each(box, function(b){
31800 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31810 Roo.each(box, function(b){
31812 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31815 mx = Math.max(mx, b.x);
31819 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31823 Roo.each(box, function(b){
31825 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31839 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31842 /** Sets position of item in DOM
31843 * @param {Element} item
31844 * @param {Number} x - horizontal position
31845 * @param {Number} y - vertical position
31846 * @param {Boolean} isInstant - disables transitions
31848 _processVerticalLayoutQueue : function( queue, isInstant )
31850 var pos = this.el.getBox(true);
31855 for (var i = 0; i < this.cols; i++){
31859 Roo.each(queue, function(box, k){
31861 var col = k % this.cols;
31863 Roo.each(box, function(b,kk){
31865 b.el.position('absolute');
31867 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31868 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31870 if(b.size == 'md-left' || b.size == 'md-right'){
31871 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31872 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31875 b.el.setWidth(width);
31876 b.el.setHeight(height);
31878 b.el.select('iframe',true).setSize(width,height);
31882 for (var i = 0; i < this.cols; i++){
31884 if(maxY[i] < maxY[col]){
31889 col = Math.min(col, i);
31893 x = pos.x + col * (this.colWidth + this.padWidth);
31897 var positions = [];
31899 switch (box.length){
31901 positions = this.getVerticalOneBoxColPositions(x, y, box);
31904 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31907 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31910 positions = this.getVerticalFourBoxColPositions(x, y, box);
31916 Roo.each(box, function(b,kk){
31918 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31920 var sz = b.el.getSize();
31922 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31930 for (var i = 0; i < this.cols; i++){
31931 mY = Math.max(mY, maxY[i]);
31934 this.el.setHeight(mY - pos.y);
31938 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31940 // var pos = this.el.getBox(true);
31943 // var maxX = pos.right;
31945 // var maxHeight = 0;
31947 // Roo.each(items, function(item, k){
31951 // item.el.position('absolute');
31953 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31955 // item.el.setWidth(width);
31957 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31959 // item.el.setHeight(height);
31962 // item.el.setXY([x, y], isInstant ? false : true);
31964 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31967 // y = y + height + this.alternativePadWidth;
31969 // maxHeight = maxHeight + height + this.alternativePadWidth;
31973 // this.el.setHeight(maxHeight);
31977 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31979 var pos = this.el.getBox(true);
31984 var maxX = pos.right;
31986 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31988 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31990 Roo.each(queue, function(box, k){
31992 Roo.each(box, function(b, kk){
31994 b.el.position('absolute');
31996 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31997 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31999 if(b.size == 'md-left' || b.size == 'md-right'){
32000 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
32001 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32004 b.el.setWidth(width);
32005 b.el.setHeight(height);
32013 var positions = [];
32015 switch (box.length){
32017 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
32020 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
32023 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
32026 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
32032 Roo.each(box, function(b,kk){
32034 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
32036 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
32044 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
32046 Roo.each(eItems, function(b,k){
32048 b.size = (k == 0) ? 'sm' : 'xs';
32049 b.x = (k == 0) ? 2 : 1;
32050 b.y = (k == 0) ? 2 : 1;
32052 b.el.position('absolute');
32054 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32056 b.el.setWidth(width);
32058 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32060 b.el.setHeight(height);
32064 var positions = [];
32067 x : maxX - this.unitWidth * 2 - this.gutter,
32072 x : maxX - this.unitWidth,
32073 y : minY + (this.unitWidth + this.gutter) * 2
32077 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32081 Roo.each(eItems, function(b,k){
32083 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32089 getVerticalOneBoxColPositions : function(x, y, box)
32093 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32095 if(box[0].size == 'md-left'){
32099 if(box[0].size == 'md-right'){
32104 x : x + (this.unitWidth + this.gutter) * rand,
32111 getVerticalTwoBoxColPositions : function(x, y, box)
32115 if(box[0].size == 'xs'){
32119 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32123 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32137 x : x + (this.unitWidth + this.gutter) * 2,
32138 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32145 getVerticalThreeBoxColPositions : function(x, y, box)
32149 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32157 x : x + (this.unitWidth + this.gutter) * 1,
32162 x : x + (this.unitWidth + this.gutter) * 2,
32170 if(box[0].size == 'xs' && box[1].size == 'xs'){
32179 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32183 x : x + (this.unitWidth + this.gutter) * 1,
32197 x : x + (this.unitWidth + this.gutter) * 2,
32202 x : x + (this.unitWidth + this.gutter) * 2,
32203 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32210 getVerticalFourBoxColPositions : function(x, y, box)
32214 if(box[0].size == 'xs'){
32223 y : y + (this.unitHeight + this.gutter) * 1
32228 y : y + (this.unitHeight + this.gutter) * 2
32232 x : x + (this.unitWidth + this.gutter) * 1,
32246 x : x + (this.unitWidth + this.gutter) * 2,
32251 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32252 y : y + (this.unitHeight + this.gutter) * 1
32256 x : x + (this.unitWidth + this.gutter) * 2,
32257 y : y + (this.unitWidth + this.gutter) * 2
32264 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32268 if(box[0].size == 'md-left'){
32270 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32277 if(box[0].size == 'md-right'){
32279 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32280 y : minY + (this.unitWidth + this.gutter) * 1
32286 var rand = Math.floor(Math.random() * (4 - box[0].y));
32289 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32290 y : minY + (this.unitWidth + this.gutter) * rand
32297 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32301 if(box[0].size == 'xs'){
32304 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32309 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32310 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32318 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32323 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32324 y : minY + (this.unitWidth + this.gutter) * 2
32331 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32335 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32338 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32343 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32344 y : minY + (this.unitWidth + this.gutter) * 1
32348 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32349 y : minY + (this.unitWidth + this.gutter) * 2
32356 if(box[0].size == 'xs' && box[1].size == 'xs'){
32359 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32364 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32369 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32370 y : minY + (this.unitWidth + this.gutter) * 1
32378 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32383 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32384 y : minY + (this.unitWidth + this.gutter) * 2
32388 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32389 y : minY + (this.unitWidth + this.gutter) * 2
32396 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32400 if(box[0].size == 'xs'){
32403 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32408 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32413 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),
32418 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32419 y : minY + (this.unitWidth + this.gutter) * 1
32427 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32432 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32433 y : minY + (this.unitWidth + this.gutter) * 2
32437 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32438 y : minY + (this.unitWidth + this.gutter) * 2
32442 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),
32443 y : minY + (this.unitWidth + this.gutter) * 2
32451 * remove a Masonry Brick
32452 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32454 removeBrick : function(brick_id)
32460 for (var i = 0; i<this.bricks.length; i++) {
32461 if (this.bricks[i].id == brick_id) {
32462 this.bricks.splice(i,1);
32463 this.el.dom.removeChild(Roo.get(brick_id).dom);
32470 * adds a Masonry Brick
32471 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32473 addBrick : function(cfg)
32475 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32476 //this.register(cn);
32477 cn.parentId = this.id;
32478 cn.render(this.el);
32483 * register a Masonry Brick
32484 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32487 register : function(brick)
32489 this.bricks.push(brick);
32490 brick.masonryId = this.id;
32494 * clear all the Masonry Brick
32496 clearAll : function()
32499 //this.getChildContainer().dom.innerHTML = "";
32500 this.el.dom.innerHTML = '';
32503 getSelected : function()
32505 if (!this.selectedBrick) {
32509 return this.selectedBrick;
32513 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32517 * register a Masonry Layout
32518 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32521 register : function(layout)
32523 this.groups[layout.id] = layout;
32526 * fetch a Masonry Layout based on the masonry layout ID
32527 * @param {string} the masonry layout to add
32528 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32531 get: function(layout_id) {
32532 if (typeof(this.groups[layout_id]) == 'undefined') {
32535 return this.groups[layout_id] ;
32547 * http://masonry.desandro.com
32549 * The idea is to render all the bricks based on vertical width...
32551 * The original code extends 'outlayer' - we might need to use that....
32557 * @class Roo.bootstrap.LayoutMasonryAuto
32558 * @extends Roo.bootstrap.Component
32559 * Bootstrap Layout Masonry class
32562 * Create a new Element
32563 * @param {Object} config The config object
32566 Roo.bootstrap.LayoutMasonryAuto = function(config){
32567 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32570 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32573 * @cfg {Boolean} isFitWidth - resize the width..
32575 isFitWidth : false, // options..
32577 * @cfg {Boolean} isOriginLeft = left align?
32579 isOriginLeft : true,
32581 * @cfg {Boolean} isOriginTop = top align?
32583 isOriginTop : false,
32585 * @cfg {Boolean} isLayoutInstant = no animation?
32587 isLayoutInstant : false, // needed?
32589 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32591 isResizingContainer : true,
32593 * @cfg {Number} columnWidth width of the columns
32599 * @cfg {Number} maxCols maximum number of columns
32604 * @cfg {Number} padHeight padding below box..
32610 * @cfg {Boolean} isAutoInitial defalut true
32613 isAutoInitial : true,
32619 initialColumnWidth : 0,
32620 currentSize : null,
32622 colYs : null, // array.
32629 bricks: null, //CompositeElement
32630 cols : 0, // array?
32631 // element : null, // wrapped now this.el
32632 _isLayoutInited : null,
32635 getAutoCreate : function(){
32639 cls: 'blog-masonary-wrapper ' + this.cls,
32641 cls : 'mas-boxes masonary'
32648 getChildContainer: function( )
32650 if (this.boxesEl) {
32651 return this.boxesEl;
32654 this.boxesEl = this.el.select('.mas-boxes').first();
32656 return this.boxesEl;
32660 initEvents : function()
32664 if(this.isAutoInitial){
32665 Roo.log('hook children rendered');
32666 this.on('childrenrendered', function() {
32667 Roo.log('children rendered');
32674 initial : function()
32676 this.reloadItems();
32678 this.currentSize = this.el.getBox(true);
32680 /// was window resize... - let's see if this works..
32681 Roo.EventManager.onWindowResize(this.resize, this);
32683 if(!this.isAutoInitial){
32688 this.layout.defer(500,this);
32691 reloadItems: function()
32693 this.bricks = this.el.select('.masonry-brick', true);
32695 this.bricks.each(function(b) {
32696 //Roo.log(b.getSize());
32697 if (!b.attr('originalwidth')) {
32698 b.attr('originalwidth', b.getSize().width);
32703 Roo.log(this.bricks.elements.length);
32706 resize : function()
32709 var cs = this.el.getBox(true);
32711 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32712 Roo.log("no change in with or X");
32715 this.currentSize = cs;
32719 layout : function()
32722 this._resetLayout();
32723 //this._manageStamps();
32725 // don't animate first layout
32726 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32727 this.layoutItems( isInstant );
32729 // flag for initalized
32730 this._isLayoutInited = true;
32733 layoutItems : function( isInstant )
32735 //var items = this._getItemsForLayout( this.items );
32736 // original code supports filtering layout items.. we just ignore it..
32738 this._layoutItems( this.bricks , isInstant );
32740 this._postLayout();
32742 _layoutItems : function ( items , isInstant)
32744 //this.fireEvent( 'layout', this, items );
32747 if ( !items || !items.elements.length ) {
32748 // no items, emit event with empty array
32753 items.each(function(item) {
32754 Roo.log("layout item");
32756 // get x/y object from method
32757 var position = this._getItemLayoutPosition( item );
32759 position.item = item;
32760 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32761 queue.push( position );
32764 this._processLayoutQueue( queue );
32766 /** Sets position of item in DOM
32767 * @param {Element} item
32768 * @param {Number} x - horizontal position
32769 * @param {Number} y - vertical position
32770 * @param {Boolean} isInstant - disables transitions
32772 _processLayoutQueue : function( queue )
32774 for ( var i=0, len = queue.length; i < len; i++ ) {
32775 var obj = queue[i];
32776 obj.item.position('absolute');
32777 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32783 * Any logic you want to do after each layout,
32784 * i.e. size the container
32786 _postLayout : function()
32788 this.resizeContainer();
32791 resizeContainer : function()
32793 if ( !this.isResizingContainer ) {
32796 var size = this._getContainerSize();
32798 this.el.setSize(size.width,size.height);
32799 this.boxesEl.setSize(size.width,size.height);
32805 _resetLayout : function()
32807 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32808 this.colWidth = this.el.getWidth();
32809 //this.gutter = this.el.getWidth();
32811 this.measureColumns();
32817 this.colYs.push( 0 );
32823 measureColumns : function()
32825 this.getContainerWidth();
32826 // if columnWidth is 0, default to outerWidth of first item
32827 if ( !this.columnWidth ) {
32828 var firstItem = this.bricks.first();
32829 Roo.log(firstItem);
32830 this.columnWidth = this.containerWidth;
32831 if (firstItem && firstItem.attr('originalwidth') ) {
32832 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32834 // columnWidth fall back to item of first element
32835 Roo.log("set column width?");
32836 this.initialColumnWidth = this.columnWidth ;
32838 // if first elem has no width, default to size of container
32843 if (this.initialColumnWidth) {
32844 this.columnWidth = this.initialColumnWidth;
32849 // column width is fixed at the top - however if container width get's smaller we should
32852 // this bit calcs how man columns..
32854 var columnWidth = this.columnWidth += this.gutter;
32856 // calculate columns
32857 var containerWidth = this.containerWidth + this.gutter;
32859 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32860 // fix rounding errors, typically with gutters
32861 var excess = columnWidth - containerWidth % columnWidth;
32864 // if overshoot is less than a pixel, round up, otherwise floor it
32865 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32866 cols = Math[ mathMethod ]( cols );
32867 this.cols = Math.max( cols, 1 );
32868 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32870 // padding positioning..
32871 var totalColWidth = this.cols * this.columnWidth;
32872 var padavail = this.containerWidth - totalColWidth;
32873 // so for 2 columns - we need 3 'pads'
32875 var padNeeded = (1+this.cols) * this.padWidth;
32877 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32879 this.columnWidth += padExtra
32880 //this.padWidth = Math.floor(padavail / ( this.cols));
32882 // adjust colum width so that padding is fixed??
32884 // we have 3 columns ... total = width * 3
32885 // we have X left over... that should be used by
32887 //if (this.expandC) {
32895 getContainerWidth : function()
32897 /* // container is parent if fit width
32898 var container = this.isFitWidth ? this.element.parentNode : this.element;
32899 // check that this.size and size are there
32900 // IE8 triggers resize on body size change, so they might not be
32902 var size = getSize( container ); //FIXME
32903 this.containerWidth = size && size.innerWidth; //FIXME
32906 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32910 _getItemLayoutPosition : function( item ) // what is item?
32912 // we resize the item to our columnWidth..
32914 item.setWidth(this.columnWidth);
32915 item.autoBoxAdjust = false;
32917 var sz = item.getSize();
32919 // how many columns does this brick span
32920 var remainder = this.containerWidth % this.columnWidth;
32922 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32923 // round if off by 1 pixel, otherwise use ceil
32924 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32925 colSpan = Math.min( colSpan, this.cols );
32927 // normally this should be '1' as we dont' currently allow multi width columns..
32929 var colGroup = this._getColGroup( colSpan );
32930 // get the minimum Y value from the columns
32931 var minimumY = Math.min.apply( Math, colGroup );
32932 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32934 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32936 // position the brick
32938 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32939 y: this.currentSize.y + minimumY + this.padHeight
32943 // apply setHeight to necessary columns
32944 var setHeight = minimumY + sz.height + this.padHeight;
32945 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32947 var setSpan = this.cols + 1 - colGroup.length;
32948 for ( var i = 0; i < setSpan; i++ ) {
32949 this.colYs[ shortColIndex + i ] = setHeight ;
32956 * @param {Number} colSpan - number of columns the element spans
32957 * @returns {Array} colGroup
32959 _getColGroup : function( colSpan )
32961 if ( colSpan < 2 ) {
32962 // if brick spans only one column, use all the column Ys
32967 // how many different places could this brick fit horizontally
32968 var groupCount = this.cols + 1 - colSpan;
32969 // for each group potential horizontal position
32970 for ( var i = 0; i < groupCount; i++ ) {
32971 // make an array of colY values for that one group
32972 var groupColYs = this.colYs.slice( i, i + colSpan );
32973 // and get the max value of the array
32974 colGroup[i] = Math.max.apply( Math, groupColYs );
32979 _manageStamp : function( stamp )
32981 var stampSize = stamp.getSize();
32982 var offset = stamp.getBox();
32983 // get the columns that this stamp affects
32984 var firstX = this.isOriginLeft ? offset.x : offset.right;
32985 var lastX = firstX + stampSize.width;
32986 var firstCol = Math.floor( firstX / this.columnWidth );
32987 firstCol = Math.max( 0, firstCol );
32989 var lastCol = Math.floor( lastX / this.columnWidth );
32990 // lastCol should not go over if multiple of columnWidth #425
32991 lastCol -= lastX % this.columnWidth ? 0 : 1;
32992 lastCol = Math.min( this.cols - 1, lastCol );
32994 // set colYs to bottom of the stamp
32995 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32998 for ( var i = firstCol; i <= lastCol; i++ ) {
32999 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
33004 _getContainerSize : function()
33006 this.maxY = Math.max.apply( Math, this.colYs );
33011 if ( this.isFitWidth ) {
33012 size.width = this._getContainerFitWidth();
33018 _getContainerFitWidth : function()
33020 var unusedCols = 0;
33021 // count unused columns
33024 if ( this.colYs[i] !== 0 ) {
33029 // fit container to columns that have been used
33030 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
33033 needsResizeLayout : function()
33035 var previousWidth = this.containerWidth;
33036 this.getContainerWidth();
33037 return previousWidth !== this.containerWidth;
33052 * @class Roo.bootstrap.MasonryBrick
33053 * @extends Roo.bootstrap.Component
33054 * Bootstrap MasonryBrick class
33057 * Create a new MasonryBrick
33058 * @param {Object} config The config object
33061 Roo.bootstrap.MasonryBrick = function(config){
33063 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
33065 Roo.bootstrap.MasonryBrick.register(this);
33071 * When a MasonryBrick is clcik
33072 * @param {Roo.bootstrap.MasonryBrick} this
33073 * @param {Roo.EventObject} e
33079 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33082 * @cfg {String} title
33086 * @cfg {String} html
33090 * @cfg {String} bgimage
33094 * @cfg {String} videourl
33098 * @cfg {String} cls
33102 * @cfg {String} href
33106 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33111 * @cfg {String} placetitle (center|bottom)
33116 * @cfg {Boolean} isFitContainer defalut true
33118 isFitContainer : true,
33121 * @cfg {Boolean} preventDefault defalut false
33123 preventDefault : false,
33126 * @cfg {Boolean} inverse defalut false
33128 maskInverse : false,
33130 getAutoCreate : function()
33132 if(!this.isFitContainer){
33133 return this.getSplitAutoCreate();
33136 var cls = 'masonry-brick masonry-brick-full';
33138 if(this.href.length){
33139 cls += ' masonry-brick-link';
33142 if(this.bgimage.length){
33143 cls += ' masonry-brick-image';
33146 if(this.maskInverse){
33147 cls += ' mask-inverse';
33150 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33151 cls += ' enable-mask';
33155 cls += ' masonry-' + this.size + '-brick';
33158 if(this.placetitle.length){
33160 switch (this.placetitle) {
33162 cls += ' masonry-center-title';
33165 cls += ' masonry-bottom-title';
33172 if(!this.html.length && !this.bgimage.length){
33173 cls += ' masonry-center-title';
33176 if(!this.html.length && this.bgimage.length){
33177 cls += ' masonry-bottom-title';
33182 cls += ' ' + this.cls;
33186 tag: (this.href.length) ? 'a' : 'div',
33191 cls: 'masonry-brick-mask'
33195 cls: 'masonry-brick-paragraph',
33201 if(this.href.length){
33202 cfg.href = this.href;
33205 var cn = cfg.cn[1].cn;
33207 if(this.title.length){
33210 cls: 'masonry-brick-title',
33215 if(this.html.length){
33218 cls: 'masonry-brick-text',
33223 if (!this.title.length && !this.html.length) {
33224 cfg.cn[1].cls += ' hide';
33227 if(this.bgimage.length){
33230 cls: 'masonry-brick-image-view',
33235 if(this.videourl.length){
33236 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33237 // youtube support only?
33240 cls: 'masonry-brick-image-view',
33243 allowfullscreen : true
33251 getSplitAutoCreate : function()
33253 var cls = 'masonry-brick masonry-brick-split';
33255 if(this.href.length){
33256 cls += ' masonry-brick-link';
33259 if(this.bgimage.length){
33260 cls += ' masonry-brick-image';
33264 cls += ' masonry-' + this.size + '-brick';
33267 switch (this.placetitle) {
33269 cls += ' masonry-center-title';
33272 cls += ' masonry-bottom-title';
33275 if(!this.bgimage.length){
33276 cls += ' masonry-center-title';
33279 if(this.bgimage.length){
33280 cls += ' masonry-bottom-title';
33286 cls += ' ' + this.cls;
33290 tag: (this.href.length) ? 'a' : 'div',
33295 cls: 'masonry-brick-split-head',
33299 cls: 'masonry-brick-paragraph',
33306 cls: 'masonry-brick-split-body',
33312 if(this.href.length){
33313 cfg.href = this.href;
33316 if(this.title.length){
33317 cfg.cn[0].cn[0].cn.push({
33319 cls: 'masonry-brick-title',
33324 if(this.html.length){
33325 cfg.cn[1].cn.push({
33327 cls: 'masonry-brick-text',
33332 if(this.bgimage.length){
33333 cfg.cn[0].cn.push({
33335 cls: 'masonry-brick-image-view',
33340 if(this.videourl.length){
33341 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33342 // youtube support only?
33343 cfg.cn[0].cn.cn.push({
33345 cls: 'masonry-brick-image-view',
33348 allowfullscreen : true
33355 initEvents: function()
33357 switch (this.size) {
33390 this.el.on('touchstart', this.onTouchStart, this);
33391 this.el.on('touchmove', this.onTouchMove, this);
33392 this.el.on('touchend', this.onTouchEnd, this);
33393 this.el.on('contextmenu', this.onContextMenu, this);
33395 this.el.on('mouseenter' ,this.enter, this);
33396 this.el.on('mouseleave', this.leave, this);
33397 this.el.on('click', this.onClick, this);
33400 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33401 this.parent().bricks.push(this);
33406 onClick: function(e, el)
33408 var time = this.endTimer - this.startTimer;
33409 // Roo.log(e.preventDefault());
33412 e.preventDefault();
33417 if(!this.preventDefault){
33421 e.preventDefault();
33423 if (this.activeClass != '') {
33424 this.selectBrick();
33427 this.fireEvent('click', this, e);
33430 enter: function(e, el)
33432 e.preventDefault();
33434 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33438 if(this.bgimage.length && this.html.length){
33439 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33443 leave: function(e, el)
33445 e.preventDefault();
33447 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33451 if(this.bgimage.length && this.html.length){
33452 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33456 onTouchStart: function(e, el)
33458 // e.preventDefault();
33460 this.touchmoved = false;
33462 if(!this.isFitContainer){
33466 if(!this.bgimage.length || !this.html.length){
33470 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33472 this.timer = new Date().getTime();
33476 onTouchMove: function(e, el)
33478 this.touchmoved = true;
33481 onContextMenu : function(e,el)
33483 e.preventDefault();
33484 e.stopPropagation();
33488 onTouchEnd: function(e, el)
33490 // e.preventDefault();
33492 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33499 if(!this.bgimage.length || !this.html.length){
33501 if(this.href.length){
33502 window.location.href = this.href;
33508 if(!this.isFitContainer){
33512 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33514 window.location.href = this.href;
33517 //selection on single brick only
33518 selectBrick : function() {
33520 if (!this.parentId) {
33524 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33525 var index = m.selectedBrick.indexOf(this.id);
33528 m.selectedBrick.splice(index,1);
33529 this.el.removeClass(this.activeClass);
33533 for(var i = 0; i < m.selectedBrick.length; i++) {
33534 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33535 b.el.removeClass(b.activeClass);
33538 m.selectedBrick = [];
33540 m.selectedBrick.push(this.id);
33541 this.el.addClass(this.activeClass);
33545 isSelected : function(){
33546 return this.el.hasClass(this.activeClass);
33551 Roo.apply(Roo.bootstrap.MasonryBrick, {
33554 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33556 * register a Masonry Brick
33557 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33560 register : function(brick)
33562 //this.groups[brick.id] = brick;
33563 this.groups.add(brick.id, brick);
33566 * fetch a masonry brick based on the masonry brick ID
33567 * @param {string} the masonry brick to add
33568 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33571 get: function(brick_id)
33573 // if (typeof(this.groups[brick_id]) == 'undefined') {
33576 // return this.groups[brick_id] ;
33578 if(this.groups.key(brick_id)) {
33579 return this.groups.key(brick_id);
33597 * @class Roo.bootstrap.Brick
33598 * @extends Roo.bootstrap.Component
33599 * Bootstrap Brick class
33602 * Create a new Brick
33603 * @param {Object} config The config object
33606 Roo.bootstrap.Brick = function(config){
33607 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33613 * When a Brick is click
33614 * @param {Roo.bootstrap.Brick} this
33615 * @param {Roo.EventObject} e
33621 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33624 * @cfg {String} title
33628 * @cfg {String} html
33632 * @cfg {String} bgimage
33636 * @cfg {String} cls
33640 * @cfg {String} href
33644 * @cfg {String} video
33648 * @cfg {Boolean} square
33652 getAutoCreate : function()
33654 var cls = 'roo-brick';
33656 if(this.href.length){
33657 cls += ' roo-brick-link';
33660 if(this.bgimage.length){
33661 cls += ' roo-brick-image';
33664 if(!this.html.length && !this.bgimage.length){
33665 cls += ' roo-brick-center-title';
33668 if(!this.html.length && this.bgimage.length){
33669 cls += ' roo-brick-bottom-title';
33673 cls += ' ' + this.cls;
33677 tag: (this.href.length) ? 'a' : 'div',
33682 cls: 'roo-brick-paragraph',
33688 if(this.href.length){
33689 cfg.href = this.href;
33692 var cn = cfg.cn[0].cn;
33694 if(this.title.length){
33697 cls: 'roo-brick-title',
33702 if(this.html.length){
33705 cls: 'roo-brick-text',
33712 if(this.bgimage.length){
33715 cls: 'roo-brick-image-view',
33723 initEvents: function()
33725 if(this.title.length || this.html.length){
33726 this.el.on('mouseenter' ,this.enter, this);
33727 this.el.on('mouseleave', this.leave, this);
33730 Roo.EventManager.onWindowResize(this.resize, this);
33732 if(this.bgimage.length){
33733 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33734 this.imageEl.on('load', this.onImageLoad, this);
33741 onImageLoad : function()
33746 resize : function()
33748 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33750 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33752 if(this.bgimage.length){
33753 var image = this.el.select('.roo-brick-image-view', true).first();
33755 image.setWidth(paragraph.getWidth());
33758 image.setHeight(paragraph.getWidth());
33761 this.el.setHeight(image.getHeight());
33762 paragraph.setHeight(image.getHeight());
33768 enter: function(e, el)
33770 e.preventDefault();
33772 if(this.bgimage.length){
33773 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33774 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33778 leave: function(e, el)
33780 e.preventDefault();
33782 if(this.bgimage.length){
33783 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33784 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33799 * @class Roo.bootstrap.NumberField
33800 * @extends Roo.bootstrap.Input
33801 * Bootstrap NumberField class
33807 * Create a new NumberField
33808 * @param {Object} config The config object
33811 Roo.bootstrap.NumberField = function(config){
33812 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33815 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33818 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33820 allowDecimals : true,
33822 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33824 decimalSeparator : ".",
33826 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33828 decimalPrecision : 2,
33830 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33832 allowNegative : true,
33835 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33839 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33841 minValue : Number.NEGATIVE_INFINITY,
33843 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33845 maxValue : Number.MAX_VALUE,
33847 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33849 minText : "The minimum value for this field is {0}",
33851 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33853 maxText : "The maximum value for this field is {0}",
33855 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33856 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33858 nanText : "{0} is not a valid number",
33860 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33862 thousandsDelimiter : false,
33864 * @cfg {String} valueAlign alignment of value
33866 valueAlign : "left",
33868 getAutoCreate : function()
33870 var hiddenInput = {
33874 cls: 'hidden-number-input'
33878 hiddenInput.name = this.name;
33883 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33885 this.name = hiddenInput.name;
33887 if(cfg.cn.length > 0) {
33888 cfg.cn.push(hiddenInput);
33895 initEvents : function()
33897 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33899 var allowed = "0123456789";
33901 if(this.allowDecimals){
33902 allowed += this.decimalSeparator;
33905 if(this.allowNegative){
33909 if(this.thousandsDelimiter) {
33913 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33915 var keyPress = function(e){
33917 var k = e.getKey();
33919 var c = e.getCharCode();
33922 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33923 allowed.indexOf(String.fromCharCode(c)) === -1
33929 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33933 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33938 this.el.on("keypress", keyPress, this);
33941 validateValue : function(value)
33944 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33948 var num = this.parseValue(value);
33951 this.markInvalid(String.format(this.nanText, value));
33955 if(num < this.minValue){
33956 this.markInvalid(String.format(this.minText, this.minValue));
33960 if(num > this.maxValue){
33961 this.markInvalid(String.format(this.maxText, this.maxValue));
33968 getValue : function()
33970 var v = this.hiddenEl().getValue();
33972 return this.fixPrecision(this.parseValue(v));
33975 parseValue : function(value)
33977 if(this.thousandsDelimiter) {
33979 r = new RegExp(",", "g");
33980 value = value.replace(r, "");
33983 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33984 return isNaN(value) ? '' : value;
33987 fixPrecision : function(value)
33989 if(this.thousandsDelimiter) {
33991 r = new RegExp(",", "g");
33992 value = value.replace(r, "");
33995 var nan = isNaN(value);
33997 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33998 return nan ? '' : value;
34000 return parseFloat(value).toFixed(this.decimalPrecision);
34003 setValue : function(v)
34005 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
34011 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
34013 this.inputEl().dom.value = (v == '') ? '' :
34014 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
34016 if(!this.allowZero && v === '0') {
34017 this.hiddenEl().dom.value = '';
34018 this.inputEl().dom.value = '';
34025 decimalPrecisionFcn : function(v)
34027 return Math.floor(v);
34030 beforeBlur : function()
34032 var v = this.parseValue(this.getRawValue());
34034 if(v || v === 0 || v === ''){
34039 hiddenEl : function()
34041 return this.el.select('input.hidden-number-input',true).first();
34053 * @class Roo.bootstrap.DocumentSlider
34054 * @extends Roo.bootstrap.Component
34055 * Bootstrap DocumentSlider class
34058 * Create a new DocumentViewer
34059 * @param {Object} config The config object
34062 Roo.bootstrap.DocumentSlider = function(config){
34063 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34070 * Fire after initEvent
34071 * @param {Roo.bootstrap.DocumentSlider} this
34076 * Fire after update
34077 * @param {Roo.bootstrap.DocumentSlider} this
34083 * @param {Roo.bootstrap.DocumentSlider} this
34089 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34095 getAutoCreate : function()
34099 cls : 'roo-document-slider',
34103 cls : 'roo-document-slider-header',
34107 cls : 'roo-document-slider-header-title'
34113 cls : 'roo-document-slider-body',
34117 cls : 'roo-document-slider-prev',
34121 cls : 'fa fa-chevron-left'
34127 cls : 'roo-document-slider-thumb',
34131 cls : 'roo-document-slider-image'
34137 cls : 'roo-document-slider-next',
34141 cls : 'fa fa-chevron-right'
34153 initEvents : function()
34155 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34156 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34158 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34159 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34161 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34162 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34164 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34165 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34167 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34168 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34170 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34171 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34173 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34174 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34176 this.thumbEl.on('click', this.onClick, this);
34178 this.prevIndicator.on('click', this.prev, this);
34180 this.nextIndicator.on('click', this.next, this);
34184 initial : function()
34186 if(this.files.length){
34187 this.indicator = 1;
34191 this.fireEvent('initial', this);
34194 update : function()
34196 this.imageEl.attr('src', this.files[this.indicator - 1]);
34198 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34200 this.prevIndicator.show();
34202 if(this.indicator == 1){
34203 this.prevIndicator.hide();
34206 this.nextIndicator.show();
34208 if(this.indicator == this.files.length){
34209 this.nextIndicator.hide();
34212 this.thumbEl.scrollTo('top');
34214 this.fireEvent('update', this);
34217 onClick : function(e)
34219 e.preventDefault();
34221 this.fireEvent('click', this);
34226 e.preventDefault();
34228 this.indicator = Math.max(1, this.indicator - 1);
34235 e.preventDefault();
34237 this.indicator = Math.min(this.files.length, this.indicator + 1);
34251 * @class Roo.bootstrap.RadioSet
34252 * @extends Roo.bootstrap.Input
34253 * Bootstrap RadioSet class
34254 * @cfg {String} indicatorpos (left|right) default left
34255 * @cfg {Boolean} inline (true|false) inline the element (default true)
34256 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34258 * Create a new RadioSet
34259 * @param {Object} config The config object
34262 Roo.bootstrap.RadioSet = function(config){
34264 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34268 Roo.bootstrap.RadioSet.register(this);
34273 * Fires when the element is checked or unchecked.
34274 * @param {Roo.bootstrap.RadioSet} this This radio
34275 * @param {Roo.bootstrap.Radio} item The checked item
34280 * Fires when the element is click.
34281 * @param {Roo.bootstrap.RadioSet} this This radio set
34282 * @param {Roo.bootstrap.Radio} item The checked item
34283 * @param {Roo.EventObject} e The event object
34290 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34298 indicatorpos : 'left',
34300 getAutoCreate : function()
34304 cls : 'roo-radio-set-label',
34308 html : this.fieldLabel
34312 if (Roo.bootstrap.version == 3) {
34315 if(this.indicatorpos == 'left'){
34318 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34319 tooltip : 'This field is required'
34324 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34325 tooltip : 'This field is required'
34331 cls : 'roo-radio-set-items'
34334 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34336 if (align === 'left' && this.fieldLabel.length) {
34339 cls : "roo-radio-set-right",
34345 if(this.labelWidth > 12){
34346 label.style = "width: " + this.labelWidth + 'px';
34349 if(this.labelWidth < 13 && this.labelmd == 0){
34350 this.labelmd = this.labelWidth;
34353 if(this.labellg > 0){
34354 label.cls += ' col-lg-' + this.labellg;
34355 items.cls += ' col-lg-' + (12 - this.labellg);
34358 if(this.labelmd > 0){
34359 label.cls += ' col-md-' + this.labelmd;
34360 items.cls += ' col-md-' + (12 - this.labelmd);
34363 if(this.labelsm > 0){
34364 label.cls += ' col-sm-' + this.labelsm;
34365 items.cls += ' col-sm-' + (12 - this.labelsm);
34368 if(this.labelxs > 0){
34369 label.cls += ' col-xs-' + this.labelxs;
34370 items.cls += ' col-xs-' + (12 - this.labelxs);
34376 cls : 'roo-radio-set',
34380 cls : 'roo-radio-set-input',
34383 value : this.value ? this.value : ''
34390 if(this.weight.length){
34391 cfg.cls += ' roo-radio-' + this.weight;
34395 cfg.cls += ' roo-radio-set-inline';
34399 ['xs','sm','md','lg'].map(function(size){
34400 if (settings[size]) {
34401 cfg.cls += ' col-' + size + '-' + settings[size];
34409 initEvents : function()
34411 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34412 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34414 if(!this.fieldLabel.length){
34415 this.labelEl.hide();
34418 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34419 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34421 this.indicator = this.indicatorEl();
34423 if(this.indicator){
34424 this.indicator.addClass('invisible');
34427 this.originalValue = this.getValue();
34431 inputEl: function ()
34433 return this.el.select('.roo-radio-set-input', true).first();
34436 getChildContainer : function()
34438 return this.itemsEl;
34441 register : function(item)
34443 this.radioes.push(item);
34447 validate : function()
34449 if(this.getVisibilityEl().hasClass('hidden')){
34455 Roo.each(this.radioes, function(i){
34464 if(this.allowBlank) {
34468 if(this.disabled || valid){
34473 this.markInvalid();
34478 markValid : function()
34480 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34481 this.indicatorEl().removeClass('visible');
34482 this.indicatorEl().addClass('invisible');
34486 if (Roo.bootstrap.version == 3) {
34487 this.el.removeClass([this.invalidClass, this.validClass]);
34488 this.el.addClass(this.validClass);
34490 this.el.removeClass(['is-invalid','is-valid']);
34491 this.el.addClass(['is-valid']);
34493 this.fireEvent('valid', this);
34496 markInvalid : function(msg)
34498 if(this.allowBlank || this.disabled){
34502 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34503 this.indicatorEl().removeClass('invisible');
34504 this.indicatorEl().addClass('visible');
34506 if (Roo.bootstrap.version == 3) {
34507 this.el.removeClass([this.invalidClass, this.validClass]);
34508 this.el.addClass(this.invalidClass);
34510 this.el.removeClass(['is-invalid','is-valid']);
34511 this.el.addClass(['is-invalid']);
34514 this.fireEvent('invalid', this, msg);
34518 setValue : function(v, suppressEvent)
34520 if(this.value === v){
34527 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34530 Roo.each(this.radioes, function(i){
34532 i.el.removeClass('checked');
34535 Roo.each(this.radioes, function(i){
34537 if(i.value === v || i.value.toString() === v.toString()){
34539 i.el.addClass('checked');
34541 if(suppressEvent !== true){
34542 this.fireEvent('check', this, i);
34553 clearInvalid : function(){
34555 if(!this.el || this.preventMark){
34559 this.el.removeClass([this.invalidClass]);
34561 this.fireEvent('valid', this);
34566 Roo.apply(Roo.bootstrap.RadioSet, {
34570 register : function(set)
34572 this.groups[set.name] = set;
34575 get: function(name)
34577 if (typeof(this.groups[name]) == 'undefined') {
34581 return this.groups[name] ;
34587 * Ext JS Library 1.1.1
34588 * Copyright(c) 2006-2007, Ext JS, LLC.
34590 * Originally Released Under LGPL - original licence link has changed is not relivant.
34593 * <script type="text/javascript">
34598 * @class Roo.bootstrap.SplitBar
34599 * @extends Roo.util.Observable
34600 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34604 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34605 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34606 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34607 split.minSize = 100;
34608 split.maxSize = 600;
34609 split.animate = true;
34610 split.on('moved', splitterMoved);
34613 * Create a new SplitBar
34614 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34615 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34616 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34617 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34618 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34619 position of the SplitBar).
34621 Roo.bootstrap.SplitBar = function(cfg){
34626 // dragElement : elm
34627 // resizingElement: el,
34629 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34630 // placement : Roo.bootstrap.SplitBar.LEFT ,
34631 // existingProxy ???
34634 this.el = Roo.get(cfg.dragElement, true);
34635 this.el.dom.unselectable = "on";
34637 this.resizingEl = Roo.get(cfg.resizingElement, true);
34641 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34642 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34645 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34648 * The minimum size of the resizing element. (Defaults to 0)
34654 * The maximum size of the resizing element. (Defaults to 2000)
34657 this.maxSize = 2000;
34660 * Whether to animate the transition to the new size
34663 this.animate = false;
34666 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34669 this.useShim = false;
34674 if(!cfg.existingProxy){
34676 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34678 this.proxy = Roo.get(cfg.existingProxy).dom;
34681 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34684 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34687 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34690 this.dragSpecs = {};
34693 * @private The adapter to use to positon and resize elements
34695 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34696 this.adapter.init(this);
34698 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34700 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34701 this.el.addClass("roo-splitbar-h");
34704 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34705 this.el.addClass("roo-splitbar-v");
34711 * Fires when the splitter is moved (alias for {@link #event-moved})
34712 * @param {Roo.bootstrap.SplitBar} this
34713 * @param {Number} newSize the new width or height
34718 * Fires when the splitter is moved
34719 * @param {Roo.bootstrap.SplitBar} this
34720 * @param {Number} newSize the new width or height
34724 * @event beforeresize
34725 * Fires before the splitter is dragged
34726 * @param {Roo.bootstrap.SplitBar} this
34728 "beforeresize" : true,
34730 "beforeapply" : true
34733 Roo.util.Observable.call(this);
34736 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34737 onStartProxyDrag : function(x, y){
34738 this.fireEvent("beforeresize", this);
34740 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34742 o.enableDisplayMode("block");
34743 // all splitbars share the same overlay
34744 Roo.bootstrap.SplitBar.prototype.overlay = o;
34746 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34747 this.overlay.show();
34748 Roo.get(this.proxy).setDisplayed("block");
34749 var size = this.adapter.getElementSize(this);
34750 this.activeMinSize = this.getMinimumSize();;
34751 this.activeMaxSize = this.getMaximumSize();;
34752 var c1 = size - this.activeMinSize;
34753 var c2 = Math.max(this.activeMaxSize - size, 0);
34754 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34755 this.dd.resetConstraints();
34756 this.dd.setXConstraint(
34757 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34758 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34760 this.dd.setYConstraint(0, 0);
34762 this.dd.resetConstraints();
34763 this.dd.setXConstraint(0, 0);
34764 this.dd.setYConstraint(
34765 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34766 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34769 this.dragSpecs.startSize = size;
34770 this.dragSpecs.startPoint = [x, y];
34771 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34775 * @private Called after the drag operation by the DDProxy
34777 onEndProxyDrag : function(e){
34778 Roo.get(this.proxy).setDisplayed(false);
34779 var endPoint = Roo.lib.Event.getXY(e);
34781 this.overlay.hide();
34784 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34785 newSize = this.dragSpecs.startSize +
34786 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34787 endPoint[0] - this.dragSpecs.startPoint[0] :
34788 this.dragSpecs.startPoint[0] - endPoint[0]
34791 newSize = this.dragSpecs.startSize +
34792 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34793 endPoint[1] - this.dragSpecs.startPoint[1] :
34794 this.dragSpecs.startPoint[1] - endPoint[1]
34797 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34798 if(newSize != this.dragSpecs.startSize){
34799 if(this.fireEvent('beforeapply', this, newSize) !== false){
34800 this.adapter.setElementSize(this, newSize);
34801 this.fireEvent("moved", this, newSize);
34802 this.fireEvent("resize", this, newSize);
34808 * Get the adapter this SplitBar uses
34809 * @return The adapter object
34811 getAdapter : function(){
34812 return this.adapter;
34816 * Set the adapter this SplitBar uses
34817 * @param {Object} adapter A SplitBar adapter object
34819 setAdapter : function(adapter){
34820 this.adapter = adapter;
34821 this.adapter.init(this);
34825 * Gets the minimum size for the resizing element
34826 * @return {Number} The minimum size
34828 getMinimumSize : function(){
34829 return this.minSize;
34833 * Sets the minimum size for the resizing element
34834 * @param {Number} minSize The minimum size
34836 setMinimumSize : function(minSize){
34837 this.minSize = minSize;
34841 * Gets the maximum size for the resizing element
34842 * @return {Number} The maximum size
34844 getMaximumSize : function(){
34845 return this.maxSize;
34849 * Sets the maximum size for the resizing element
34850 * @param {Number} maxSize The maximum size
34852 setMaximumSize : function(maxSize){
34853 this.maxSize = maxSize;
34857 * Sets the initialize size for the resizing element
34858 * @param {Number} size The initial size
34860 setCurrentSize : function(size){
34861 var oldAnimate = this.animate;
34862 this.animate = false;
34863 this.adapter.setElementSize(this, size);
34864 this.animate = oldAnimate;
34868 * Destroy this splitbar.
34869 * @param {Boolean} removeEl True to remove the element
34871 destroy : function(removeEl){
34873 this.shim.remove();
34876 this.proxy.parentNode.removeChild(this.proxy);
34884 * @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.
34886 Roo.bootstrap.SplitBar.createProxy = function(dir){
34887 var proxy = new Roo.Element(document.createElement("div"));
34888 proxy.unselectable();
34889 var cls = 'roo-splitbar-proxy';
34890 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34891 document.body.appendChild(proxy.dom);
34896 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34897 * Default Adapter. It assumes the splitter and resizing element are not positioned
34898 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34900 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34903 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34904 // do nothing for now
34905 init : function(s){
34909 * Called before drag operations to get the current size of the resizing element.
34910 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34912 getElementSize : function(s){
34913 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34914 return s.resizingEl.getWidth();
34916 return s.resizingEl.getHeight();
34921 * Called after drag operations to set the size of the resizing element.
34922 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34923 * @param {Number} newSize The new size to set
34924 * @param {Function} onComplete A function to be invoked when resizing is complete
34926 setElementSize : function(s, newSize, onComplete){
34927 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34929 s.resizingEl.setWidth(newSize);
34931 onComplete(s, newSize);
34934 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34939 s.resizingEl.setHeight(newSize);
34941 onComplete(s, newSize);
34944 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34951 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34952 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34953 * Adapter that moves the splitter element to align with the resized sizing element.
34954 * Used with an absolute positioned SplitBar.
34955 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34956 * document.body, make sure you assign an id to the body element.
34958 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34959 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34960 this.container = Roo.get(container);
34963 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34964 init : function(s){
34965 this.basic.init(s);
34968 getElementSize : function(s){
34969 return this.basic.getElementSize(s);
34972 setElementSize : function(s, newSize, onComplete){
34973 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34976 moveSplitter : function(s){
34977 var yes = Roo.bootstrap.SplitBar;
34978 switch(s.placement){
34980 s.el.setX(s.resizingEl.getRight());
34983 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34986 s.el.setY(s.resizingEl.getBottom());
34989 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34996 * Orientation constant - Create a vertical SplitBar
35000 Roo.bootstrap.SplitBar.VERTICAL = 1;
35003 * Orientation constant - Create a horizontal SplitBar
35007 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
35010 * Placement constant - The resizing element is to the left of the splitter element
35014 Roo.bootstrap.SplitBar.LEFT = 1;
35017 * Placement constant - The resizing element is to the right of the splitter element
35021 Roo.bootstrap.SplitBar.RIGHT = 2;
35024 * Placement constant - The resizing element is positioned above the splitter element
35028 Roo.bootstrap.SplitBar.TOP = 3;
35031 * Placement constant - The resizing element is positioned under splitter element
35035 Roo.bootstrap.SplitBar.BOTTOM = 4;
35036 Roo.namespace("Roo.bootstrap.layout");/*
35038 * Ext JS Library 1.1.1
35039 * Copyright(c) 2006-2007, Ext JS, LLC.
35041 * Originally Released Under LGPL - original licence link has changed is not relivant.
35044 * <script type="text/javascript">
35048 * @class Roo.bootstrap.layout.Manager
35049 * @extends Roo.bootstrap.Component
35050 * Base class for layout managers.
35052 Roo.bootstrap.layout.Manager = function(config)
35054 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
35060 /** false to disable window resize monitoring @type Boolean */
35061 this.monitorWindowResize = true;
35066 * Fires when a layout is performed.
35067 * @param {Roo.LayoutManager} this
35071 * @event regionresized
35072 * Fires when the user resizes a region.
35073 * @param {Roo.LayoutRegion} region The resized region
35074 * @param {Number} newSize The new size (width for east/west, height for north/south)
35076 "regionresized" : true,
35078 * @event regioncollapsed
35079 * Fires when a region is collapsed.
35080 * @param {Roo.LayoutRegion} region The collapsed region
35082 "regioncollapsed" : true,
35084 * @event regionexpanded
35085 * Fires when a region is expanded.
35086 * @param {Roo.LayoutRegion} region The expanded region
35088 "regionexpanded" : true
35090 this.updating = false;
35093 this.el = Roo.get(config.el);
35099 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35104 monitorWindowResize : true,
35110 onRender : function(ct, position)
35113 this.el = Roo.get(ct);
35116 //this.fireEvent('render',this);
35120 initEvents: function()
35124 // ie scrollbar fix
35125 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35126 document.body.scroll = "no";
35127 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35128 this.el.position('relative');
35130 this.id = this.el.id;
35131 this.el.addClass("roo-layout-container");
35132 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35133 if(this.el.dom != document.body ) {
35134 this.el.on('resize', this.layout,this);
35135 this.el.on('show', this.layout,this);
35141 * Returns true if this layout is currently being updated
35142 * @return {Boolean}
35144 isUpdating : function(){
35145 return this.updating;
35149 * Suspend the LayoutManager from doing auto-layouts while
35150 * making multiple add or remove calls
35152 beginUpdate : function(){
35153 this.updating = true;
35157 * Restore auto-layouts and optionally disable the manager from performing a layout
35158 * @param {Boolean} noLayout true to disable a layout update
35160 endUpdate : function(noLayout){
35161 this.updating = false;
35167 layout: function(){
35171 onRegionResized : function(region, newSize){
35172 this.fireEvent("regionresized", region, newSize);
35176 onRegionCollapsed : function(region){
35177 this.fireEvent("regioncollapsed", region);
35180 onRegionExpanded : function(region){
35181 this.fireEvent("regionexpanded", region);
35185 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35186 * performs box-model adjustments.
35187 * @return {Object} The size as an object {width: (the width), height: (the height)}
35189 getViewSize : function()
35192 if(this.el.dom != document.body){
35193 size = this.el.getSize();
35195 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35197 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35198 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35203 * Returns the Element this layout is bound to.
35204 * @return {Roo.Element}
35206 getEl : function(){
35211 * Returns the specified region.
35212 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35213 * @return {Roo.LayoutRegion}
35215 getRegion : function(target){
35216 return this.regions[target.toLowerCase()];
35219 onWindowResize : function(){
35220 if(this.monitorWindowResize){
35227 * Ext JS Library 1.1.1
35228 * Copyright(c) 2006-2007, Ext JS, LLC.
35230 * Originally Released Under LGPL - original licence link has changed is not relivant.
35233 * <script type="text/javascript">
35236 * @class Roo.bootstrap.layout.Border
35237 * @extends Roo.bootstrap.layout.Manager
35238 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35239 * please see: examples/bootstrap/nested.html<br><br>
35241 <b>The container the layout is rendered into can be either the body element or any other element.
35242 If it is not the body element, the container needs to either be an absolute positioned element,
35243 or you will need to add "position:relative" to the css of the container. You will also need to specify
35244 the container size if it is not the body element.</b>
35247 * Create a new Border
35248 * @param {Object} config Configuration options
35250 Roo.bootstrap.layout.Border = function(config){
35251 config = config || {};
35252 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35256 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35257 if(config[region]){
35258 config[region].region = region;
35259 this.addRegion(config[region]);
35265 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35267 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35269 parent : false, // this might point to a 'nest' or a ???
35272 * Creates and adds a new region if it doesn't already exist.
35273 * @param {String} target The target region key (north, south, east, west or center).
35274 * @param {Object} config The regions config object
35275 * @return {BorderLayoutRegion} The new region
35277 addRegion : function(config)
35279 if(!this.regions[config.region]){
35280 var r = this.factory(config);
35281 this.bindRegion(r);
35283 return this.regions[config.region];
35287 bindRegion : function(r){
35288 this.regions[r.config.region] = r;
35290 r.on("visibilitychange", this.layout, this);
35291 r.on("paneladded", this.layout, this);
35292 r.on("panelremoved", this.layout, this);
35293 r.on("invalidated", this.layout, this);
35294 r.on("resized", this.onRegionResized, this);
35295 r.on("collapsed", this.onRegionCollapsed, this);
35296 r.on("expanded", this.onRegionExpanded, this);
35300 * Performs a layout update.
35302 layout : function()
35304 if(this.updating) {
35308 // render all the rebions if they have not been done alreayd?
35309 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35310 if(this.regions[region] && !this.regions[region].bodyEl){
35311 this.regions[region].onRender(this.el)
35315 var size = this.getViewSize();
35316 var w = size.width;
35317 var h = size.height;
35322 //var x = 0, y = 0;
35324 var rs = this.regions;
35325 var north = rs["north"];
35326 var south = rs["south"];
35327 var west = rs["west"];
35328 var east = rs["east"];
35329 var center = rs["center"];
35330 //if(this.hideOnLayout){ // not supported anymore
35331 //c.el.setStyle("display", "none");
35333 if(north && north.isVisible()){
35334 var b = north.getBox();
35335 var m = north.getMargins();
35336 b.width = w - (m.left+m.right);
35339 centerY = b.height + b.y + m.bottom;
35340 centerH -= centerY;
35341 north.updateBox(this.safeBox(b));
35343 if(south && south.isVisible()){
35344 var b = south.getBox();
35345 var m = south.getMargins();
35346 b.width = w - (m.left+m.right);
35348 var totalHeight = (b.height + m.top + m.bottom);
35349 b.y = h - totalHeight + m.top;
35350 centerH -= totalHeight;
35351 south.updateBox(this.safeBox(b));
35353 if(west && west.isVisible()){
35354 var b = west.getBox();
35355 var m = west.getMargins();
35356 b.height = centerH - (m.top+m.bottom);
35358 b.y = centerY + m.top;
35359 var totalWidth = (b.width + m.left + m.right);
35360 centerX += totalWidth;
35361 centerW -= totalWidth;
35362 west.updateBox(this.safeBox(b));
35364 if(east && east.isVisible()){
35365 var b = east.getBox();
35366 var m = east.getMargins();
35367 b.height = centerH - (m.top+m.bottom);
35368 var totalWidth = (b.width + m.left + m.right);
35369 b.x = w - totalWidth + m.left;
35370 b.y = centerY + m.top;
35371 centerW -= totalWidth;
35372 east.updateBox(this.safeBox(b));
35375 var m = center.getMargins();
35377 x: centerX + m.left,
35378 y: centerY + m.top,
35379 width: centerW - (m.left+m.right),
35380 height: centerH - (m.top+m.bottom)
35382 //if(this.hideOnLayout){
35383 //center.el.setStyle("display", "block");
35385 center.updateBox(this.safeBox(centerBox));
35388 this.fireEvent("layout", this);
35392 safeBox : function(box){
35393 box.width = Math.max(0, box.width);
35394 box.height = Math.max(0, box.height);
35399 * Adds a ContentPanel (or subclass) to this layout.
35400 * @param {String} target The target region key (north, south, east, west or center).
35401 * @param {Roo.ContentPanel} panel The panel to add
35402 * @return {Roo.ContentPanel} The added panel
35404 add : function(target, panel){
35406 target = target.toLowerCase();
35407 return this.regions[target].add(panel);
35411 * Remove a ContentPanel (or subclass) to this layout.
35412 * @param {String} target The target region key (north, south, east, west or center).
35413 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35414 * @return {Roo.ContentPanel} The removed panel
35416 remove : function(target, panel){
35417 target = target.toLowerCase();
35418 return this.regions[target].remove(panel);
35422 * Searches all regions for a panel with the specified id
35423 * @param {String} panelId
35424 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35426 findPanel : function(panelId){
35427 var rs = this.regions;
35428 for(var target in rs){
35429 if(typeof rs[target] != "function"){
35430 var p = rs[target].getPanel(panelId);
35440 * Searches all regions for a panel with the specified id and activates (shows) it.
35441 * @param {String/ContentPanel} panelId The panels id or the panel itself
35442 * @return {Roo.ContentPanel} The shown panel or null
35444 showPanel : function(panelId) {
35445 var rs = this.regions;
35446 for(var target in rs){
35447 var r = rs[target];
35448 if(typeof r != "function"){
35449 if(r.hasPanel(panelId)){
35450 return r.showPanel(panelId);
35458 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35459 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35462 restoreState : function(provider){
35464 provider = Roo.state.Manager;
35466 var sm = new Roo.LayoutStateManager();
35467 sm.init(this, provider);
35473 * Adds a xtype elements to the layout.
35477 xtype : 'ContentPanel',
35484 xtype : 'NestedLayoutPanel',
35490 items : [ ... list of content panels or nested layout panels.. ]
35494 * @param {Object} cfg Xtype definition of item to add.
35496 addxtype : function(cfg)
35498 // basically accepts a pannel...
35499 // can accept a layout region..!?!?
35500 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35503 // theory? children can only be panels??
35505 //if (!cfg.xtype.match(/Panel$/)) {
35510 if (typeof(cfg.region) == 'undefined') {
35511 Roo.log("Failed to add Panel, region was not set");
35515 var region = cfg.region;
35521 xitems = cfg.items;
35526 if ( region == 'center') {
35527 Roo.log("Center: " + cfg.title);
35533 case 'Content': // ContentPanel (el, cfg)
35534 case 'Scroll': // ContentPanel (el, cfg)
35536 cfg.autoCreate = cfg.autoCreate || true;
35537 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35539 // var el = this.el.createChild();
35540 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35543 this.add(region, ret);
35547 case 'TreePanel': // our new panel!
35548 cfg.el = this.el.createChild();
35549 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35550 this.add(region, ret);
35555 // create a new Layout (which is a Border Layout...
35557 var clayout = cfg.layout;
35558 clayout.el = this.el.createChild();
35559 clayout.items = clayout.items || [];
35563 // replace this exitems with the clayout ones..
35564 xitems = clayout.items;
35566 // force background off if it's in center...
35567 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35568 cfg.background = false;
35570 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35573 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35574 //console.log('adding nested layout panel ' + cfg.toSource());
35575 this.add(region, ret);
35576 nb = {}; /// find first...
35581 // needs grid and region
35583 //var el = this.getRegion(region).el.createChild();
35585 *var el = this.el.createChild();
35586 // create the grid first...
35587 cfg.grid.container = el;
35588 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35591 if (region == 'center' && this.active ) {
35592 cfg.background = false;
35595 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35597 this.add(region, ret);
35599 if (cfg.background) {
35600 // render grid on panel activation (if panel background)
35601 ret.on('activate', function(gp) {
35602 if (!gp.grid.rendered) {
35603 // gp.grid.render(el);
35607 // cfg.grid.render(el);
35613 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35614 // it was the old xcomponent building that caused this before.
35615 // espeically if border is the top element in the tree.
35625 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35627 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35628 this.add(region, ret);
35632 throw "Can not add '" + cfg.xtype + "' to Border";
35638 this.beginUpdate();
35642 Roo.each(xitems, function(i) {
35643 region = nb && i.region ? i.region : false;
35645 var add = ret.addxtype(i);
35648 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35649 if (!i.background) {
35650 abn[region] = nb[region] ;
35657 // make the last non-background panel active..
35658 //if (nb) { Roo.log(abn); }
35661 for(var r in abn) {
35662 region = this.getRegion(r);
35664 // tried using nb[r], but it does not work..
35666 region.showPanel(abn[r]);
35677 factory : function(cfg)
35680 var validRegions = Roo.bootstrap.layout.Border.regions;
35682 var target = cfg.region;
35685 var r = Roo.bootstrap.layout;
35689 return new r.North(cfg);
35691 return new r.South(cfg);
35693 return new r.East(cfg);
35695 return new r.West(cfg);
35697 return new r.Center(cfg);
35699 throw 'Layout region "'+target+'" not supported.';
35706 * Ext JS Library 1.1.1
35707 * Copyright(c) 2006-2007, Ext JS, LLC.
35709 * Originally Released Under LGPL - original licence link has changed is not relivant.
35712 * <script type="text/javascript">
35716 * @class Roo.bootstrap.layout.Basic
35717 * @extends Roo.util.Observable
35718 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35719 * and does not have a titlebar, tabs or any other features. All it does is size and position
35720 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35721 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35722 * @cfg {string} region the region that it inhabits..
35723 * @cfg {bool} skipConfig skip config?
35727 Roo.bootstrap.layout.Basic = function(config){
35729 this.mgr = config.mgr;
35731 this.position = config.region;
35733 var skipConfig = config.skipConfig;
35737 * @scope Roo.BasicLayoutRegion
35741 * @event beforeremove
35742 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35743 * @param {Roo.LayoutRegion} this
35744 * @param {Roo.ContentPanel} panel The panel
35745 * @param {Object} e The cancel event object
35747 "beforeremove" : true,
35749 * @event invalidated
35750 * Fires when the layout for this region is changed.
35751 * @param {Roo.LayoutRegion} this
35753 "invalidated" : true,
35755 * @event visibilitychange
35756 * Fires when this region is shown or hidden
35757 * @param {Roo.LayoutRegion} this
35758 * @param {Boolean} visibility true or false
35760 "visibilitychange" : true,
35762 * @event paneladded
35763 * Fires when a panel is added.
35764 * @param {Roo.LayoutRegion} this
35765 * @param {Roo.ContentPanel} panel The panel
35767 "paneladded" : true,
35769 * @event panelremoved
35770 * Fires when a panel is removed.
35771 * @param {Roo.LayoutRegion} this
35772 * @param {Roo.ContentPanel} panel The panel
35774 "panelremoved" : true,
35776 * @event beforecollapse
35777 * Fires when this region before collapse.
35778 * @param {Roo.LayoutRegion} this
35780 "beforecollapse" : true,
35783 * Fires when this region is collapsed.
35784 * @param {Roo.LayoutRegion} this
35786 "collapsed" : true,
35789 * Fires when this region is expanded.
35790 * @param {Roo.LayoutRegion} this
35795 * Fires when this region is slid into view.
35796 * @param {Roo.LayoutRegion} this
35798 "slideshow" : true,
35801 * Fires when this region slides out of view.
35802 * @param {Roo.LayoutRegion} this
35804 "slidehide" : true,
35806 * @event panelactivated
35807 * Fires when a panel is activated.
35808 * @param {Roo.LayoutRegion} this
35809 * @param {Roo.ContentPanel} panel The activated panel
35811 "panelactivated" : true,
35814 * Fires when the user resizes this region.
35815 * @param {Roo.LayoutRegion} this
35816 * @param {Number} newSize The new size (width for east/west, height for north/south)
35820 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35821 this.panels = new Roo.util.MixedCollection();
35822 this.panels.getKey = this.getPanelId.createDelegate(this);
35824 this.activePanel = null;
35825 // ensure listeners are added...
35827 if (config.listeners || config.events) {
35828 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35829 listeners : config.listeners || {},
35830 events : config.events || {}
35834 if(skipConfig !== true){
35835 this.applyConfig(config);
35839 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35841 getPanelId : function(p){
35845 applyConfig : function(config){
35846 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35847 this.config = config;
35852 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35853 * the width, for horizontal (north, south) the height.
35854 * @param {Number} newSize The new width or height
35856 resizeTo : function(newSize){
35857 var el = this.el ? this.el :
35858 (this.activePanel ? this.activePanel.getEl() : null);
35860 switch(this.position){
35863 el.setWidth(newSize);
35864 this.fireEvent("resized", this, newSize);
35868 el.setHeight(newSize);
35869 this.fireEvent("resized", this, newSize);
35875 getBox : function(){
35876 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35879 getMargins : function(){
35880 return this.margins;
35883 updateBox : function(box){
35885 var el = this.activePanel.getEl();
35886 el.dom.style.left = box.x + "px";
35887 el.dom.style.top = box.y + "px";
35888 this.activePanel.setSize(box.width, box.height);
35892 * Returns the container element for this region.
35893 * @return {Roo.Element}
35895 getEl : function(){
35896 return this.activePanel;
35900 * Returns true if this region is currently visible.
35901 * @return {Boolean}
35903 isVisible : function(){
35904 return this.activePanel ? true : false;
35907 setActivePanel : function(panel){
35908 panel = this.getPanel(panel);
35909 if(this.activePanel && this.activePanel != panel){
35910 this.activePanel.setActiveState(false);
35911 this.activePanel.getEl().setLeftTop(-10000,-10000);
35913 this.activePanel = panel;
35914 panel.setActiveState(true);
35916 panel.setSize(this.box.width, this.box.height);
35918 this.fireEvent("panelactivated", this, panel);
35919 this.fireEvent("invalidated");
35923 * Show the specified panel.
35924 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35925 * @return {Roo.ContentPanel} The shown panel or null
35927 showPanel : function(panel){
35928 panel = this.getPanel(panel);
35930 this.setActivePanel(panel);
35936 * Get the active panel for this region.
35937 * @return {Roo.ContentPanel} The active panel or null
35939 getActivePanel : function(){
35940 return this.activePanel;
35944 * Add the passed ContentPanel(s)
35945 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35946 * @return {Roo.ContentPanel} The panel added (if only one was added)
35948 add : function(panel){
35949 if(arguments.length > 1){
35950 for(var i = 0, len = arguments.length; i < len; i++) {
35951 this.add(arguments[i]);
35955 if(this.hasPanel(panel)){
35956 this.showPanel(panel);
35959 var el = panel.getEl();
35960 if(el.dom.parentNode != this.mgr.el.dom){
35961 this.mgr.el.dom.appendChild(el.dom);
35963 if(panel.setRegion){
35964 panel.setRegion(this);
35966 this.panels.add(panel);
35967 el.setStyle("position", "absolute");
35968 if(!panel.background){
35969 this.setActivePanel(panel);
35970 if(this.config.initialSize && this.panels.getCount()==1){
35971 this.resizeTo(this.config.initialSize);
35974 this.fireEvent("paneladded", this, panel);
35979 * Returns true if the panel is in this region.
35980 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35981 * @return {Boolean}
35983 hasPanel : function(panel){
35984 if(typeof panel == "object"){ // must be panel obj
35985 panel = panel.getId();
35987 return this.getPanel(panel) ? true : false;
35991 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35992 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35993 * @param {Boolean} preservePanel Overrides the config preservePanel option
35994 * @return {Roo.ContentPanel} The panel that was removed
35996 remove : function(panel, preservePanel){
35997 panel = this.getPanel(panel);
36002 this.fireEvent("beforeremove", this, panel, e);
36003 if(e.cancel === true){
36006 var panelId = panel.getId();
36007 this.panels.removeKey(panelId);
36012 * Returns the panel specified or null if it's not in this region.
36013 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36014 * @return {Roo.ContentPanel}
36016 getPanel : function(id){
36017 if(typeof id == "object"){ // must be panel obj
36020 return this.panels.get(id);
36024 * Returns this regions position (north/south/east/west/center).
36027 getPosition: function(){
36028 return this.position;
36032 * Ext JS Library 1.1.1
36033 * Copyright(c) 2006-2007, Ext JS, LLC.
36035 * Originally Released Under LGPL - original licence link has changed is not relivant.
36038 * <script type="text/javascript">
36042 * @class Roo.bootstrap.layout.Region
36043 * @extends Roo.bootstrap.layout.Basic
36044 * This class represents a region in a layout manager.
36046 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
36047 * @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})
36048 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
36049 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
36050 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
36051 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
36052 * @cfg {String} title The title for the region (overrides panel titles)
36053 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
36054 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
36055 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
36056 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
36057 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
36058 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
36059 * the space available, similar to FireFox 1.5 tabs (defaults to false)
36060 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
36061 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
36062 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
36064 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
36065 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36066 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36067 * @cfg {Number} width For East/West panels
36068 * @cfg {Number} height For North/South panels
36069 * @cfg {Boolean} split To show the splitter
36070 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36072 * @cfg {string} cls Extra CSS classes to add to region
36074 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36075 * @cfg {string} region the region that it inhabits..
36078 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36079 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36081 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36082 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36083 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36085 Roo.bootstrap.layout.Region = function(config)
36087 this.applyConfig(config);
36089 var mgr = config.mgr;
36090 var pos = config.region;
36091 config.skipConfig = true;
36092 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36095 this.onRender(mgr.el);
36098 this.visible = true;
36099 this.collapsed = false;
36100 this.unrendered_panels = [];
36103 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36105 position: '', // set by wrapper (eg. north/south etc..)
36106 unrendered_panels : null, // unrendered panels.
36108 tabPosition : false,
36110 mgr: false, // points to 'Border'
36113 createBody : function(){
36114 /** This region's body element
36115 * @type Roo.Element */
36116 this.bodyEl = this.el.createChild({
36118 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36122 onRender: function(ctr, pos)
36124 var dh = Roo.DomHelper;
36125 /** This region's container element
36126 * @type Roo.Element */
36127 this.el = dh.append(ctr.dom, {
36129 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36131 /** This region's title element
36132 * @type Roo.Element */
36134 this.titleEl = dh.append(this.el.dom, {
36136 unselectable: "on",
36137 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36139 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36140 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36144 this.titleEl.enableDisplayMode();
36145 /** This region's title text element
36146 * @type HTMLElement */
36147 this.titleTextEl = this.titleEl.dom.firstChild;
36148 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36150 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36151 this.closeBtn.enableDisplayMode();
36152 this.closeBtn.on("click", this.closeClicked, this);
36153 this.closeBtn.hide();
36155 this.createBody(this.config);
36156 if(this.config.hideWhenEmpty){
36158 this.on("paneladded", this.validateVisibility, this);
36159 this.on("panelremoved", this.validateVisibility, this);
36161 if(this.autoScroll){
36162 this.bodyEl.setStyle("overflow", "auto");
36164 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36166 //if(c.titlebar !== false){
36167 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36168 this.titleEl.hide();
36170 this.titleEl.show();
36171 if(this.config.title){
36172 this.titleTextEl.innerHTML = this.config.title;
36176 if(this.config.collapsed){
36177 this.collapse(true);
36179 if(this.config.hidden){
36183 if (this.unrendered_panels && this.unrendered_panels.length) {
36184 for (var i =0;i< this.unrendered_panels.length; i++) {
36185 this.add(this.unrendered_panels[i]);
36187 this.unrendered_panels = null;
36193 applyConfig : function(c)
36196 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36197 var dh = Roo.DomHelper;
36198 if(c.titlebar !== false){
36199 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36200 this.collapseBtn.on("click", this.collapse, this);
36201 this.collapseBtn.enableDisplayMode();
36203 if(c.showPin === true || this.showPin){
36204 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36205 this.stickBtn.enableDisplayMode();
36206 this.stickBtn.on("click", this.expand, this);
36207 this.stickBtn.hide();
36212 /** This region's collapsed element
36213 * @type Roo.Element */
36216 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36217 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36220 if(c.floatable !== false){
36221 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36222 this.collapsedEl.on("click", this.collapseClick, this);
36225 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36226 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36227 id: "message", unselectable: "on", style:{"float":"left"}});
36228 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36230 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36231 this.expandBtn.on("click", this.expand, this);
36235 if(this.collapseBtn){
36236 this.collapseBtn.setVisible(c.collapsible == true);
36239 this.cmargins = c.cmargins || this.cmargins ||
36240 (this.position == "west" || this.position == "east" ?
36241 {top: 0, left: 2, right:2, bottom: 0} :
36242 {top: 2, left: 0, right:0, bottom: 2});
36244 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36247 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36249 this.autoScroll = c.autoScroll || false;
36254 this.duration = c.duration || .30;
36255 this.slideDuration = c.slideDuration || .45;
36260 * Returns true if this region is currently visible.
36261 * @return {Boolean}
36263 isVisible : function(){
36264 return this.visible;
36268 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36269 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36271 //setCollapsedTitle : function(title){
36272 // title = title || " ";
36273 // if(this.collapsedTitleTextEl){
36274 // this.collapsedTitleTextEl.innerHTML = title;
36278 getBox : function(){
36280 // if(!this.collapsed){
36281 b = this.el.getBox(false, true);
36283 // b = this.collapsedEl.getBox(false, true);
36288 getMargins : function(){
36289 return this.margins;
36290 //return this.collapsed ? this.cmargins : this.margins;
36293 highlight : function(){
36294 this.el.addClass("x-layout-panel-dragover");
36297 unhighlight : function(){
36298 this.el.removeClass("x-layout-panel-dragover");
36301 updateBox : function(box)
36303 if (!this.bodyEl) {
36304 return; // not rendered yet..
36308 if(!this.collapsed){
36309 this.el.dom.style.left = box.x + "px";
36310 this.el.dom.style.top = box.y + "px";
36311 this.updateBody(box.width, box.height);
36313 this.collapsedEl.dom.style.left = box.x + "px";
36314 this.collapsedEl.dom.style.top = box.y + "px";
36315 this.collapsedEl.setSize(box.width, box.height);
36318 this.tabs.autoSizeTabs();
36322 updateBody : function(w, h)
36325 this.el.setWidth(w);
36326 w -= this.el.getBorderWidth("rl");
36327 if(this.config.adjustments){
36328 w += this.config.adjustments[0];
36331 if(h !== null && h > 0){
36332 this.el.setHeight(h);
36333 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36334 h -= this.el.getBorderWidth("tb");
36335 if(this.config.adjustments){
36336 h += this.config.adjustments[1];
36338 this.bodyEl.setHeight(h);
36340 h = this.tabs.syncHeight(h);
36343 if(this.panelSize){
36344 w = w !== null ? w : this.panelSize.width;
36345 h = h !== null ? h : this.panelSize.height;
36347 if(this.activePanel){
36348 var el = this.activePanel.getEl();
36349 w = w !== null ? w : el.getWidth();
36350 h = h !== null ? h : el.getHeight();
36351 this.panelSize = {width: w, height: h};
36352 this.activePanel.setSize(w, h);
36354 if(Roo.isIE && this.tabs){
36355 this.tabs.el.repaint();
36360 * Returns the container element for this region.
36361 * @return {Roo.Element}
36363 getEl : function(){
36368 * Hides this region.
36371 //if(!this.collapsed){
36372 this.el.dom.style.left = "-2000px";
36375 // this.collapsedEl.dom.style.left = "-2000px";
36376 // this.collapsedEl.hide();
36378 this.visible = false;
36379 this.fireEvent("visibilitychange", this, false);
36383 * Shows this region if it was previously hidden.
36386 //if(!this.collapsed){
36389 // this.collapsedEl.show();
36391 this.visible = true;
36392 this.fireEvent("visibilitychange", this, true);
36395 closeClicked : function(){
36396 if(this.activePanel){
36397 this.remove(this.activePanel);
36401 collapseClick : function(e){
36403 e.stopPropagation();
36406 e.stopPropagation();
36412 * Collapses this region.
36413 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36416 collapse : function(skipAnim, skipCheck = false){
36417 if(this.collapsed) {
36421 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36423 this.collapsed = true;
36425 this.split.el.hide();
36427 if(this.config.animate && skipAnim !== true){
36428 this.fireEvent("invalidated", this);
36429 this.animateCollapse();
36431 this.el.setLocation(-20000,-20000);
36433 this.collapsedEl.show();
36434 this.fireEvent("collapsed", this);
36435 this.fireEvent("invalidated", this);
36441 animateCollapse : function(){
36446 * Expands this region if it was previously collapsed.
36447 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36448 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36451 expand : function(e, skipAnim){
36453 e.stopPropagation();
36455 if(!this.collapsed || this.el.hasActiveFx()) {
36459 this.afterSlideIn();
36462 this.collapsed = false;
36463 if(this.config.animate && skipAnim !== true){
36464 this.animateExpand();
36468 this.split.el.show();
36470 this.collapsedEl.setLocation(-2000,-2000);
36471 this.collapsedEl.hide();
36472 this.fireEvent("invalidated", this);
36473 this.fireEvent("expanded", this);
36477 animateExpand : function(){
36481 initTabs : function()
36483 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36485 var ts = new Roo.bootstrap.panel.Tabs({
36486 el: this.bodyEl.dom,
36488 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36489 disableTooltips: this.config.disableTabTips,
36490 toolbar : this.config.toolbar
36493 if(this.config.hideTabs){
36494 ts.stripWrap.setDisplayed(false);
36497 ts.resizeTabs = this.config.resizeTabs === true;
36498 ts.minTabWidth = this.config.minTabWidth || 40;
36499 ts.maxTabWidth = this.config.maxTabWidth || 250;
36500 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36501 ts.monitorResize = false;
36502 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36503 ts.bodyEl.addClass('roo-layout-tabs-body');
36504 this.panels.each(this.initPanelAsTab, this);
36507 initPanelAsTab : function(panel){
36508 var ti = this.tabs.addTab(
36512 this.config.closeOnTab && panel.isClosable(),
36515 if(panel.tabTip !== undefined){
36516 ti.setTooltip(panel.tabTip);
36518 ti.on("activate", function(){
36519 this.setActivePanel(panel);
36522 if(this.config.closeOnTab){
36523 ti.on("beforeclose", function(t, e){
36525 this.remove(panel);
36529 panel.tabItem = ti;
36534 updatePanelTitle : function(panel, title)
36536 if(this.activePanel == panel){
36537 this.updateTitle(title);
36540 var ti = this.tabs.getTab(panel.getEl().id);
36542 if(panel.tabTip !== undefined){
36543 ti.setTooltip(panel.tabTip);
36548 updateTitle : function(title){
36549 if(this.titleTextEl && !this.config.title){
36550 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36554 setActivePanel : function(panel)
36556 panel = this.getPanel(panel);
36557 if(this.activePanel && this.activePanel != panel){
36558 if(this.activePanel.setActiveState(false) === false){
36562 this.activePanel = panel;
36563 panel.setActiveState(true);
36564 if(this.panelSize){
36565 panel.setSize(this.panelSize.width, this.panelSize.height);
36568 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36570 this.updateTitle(panel.getTitle());
36572 this.fireEvent("invalidated", this);
36574 this.fireEvent("panelactivated", this, panel);
36578 * Shows the specified panel.
36579 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36580 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36582 showPanel : function(panel)
36584 panel = this.getPanel(panel);
36587 var tab = this.tabs.getTab(panel.getEl().id);
36588 if(tab.isHidden()){
36589 this.tabs.unhideTab(tab.id);
36593 this.setActivePanel(panel);
36600 * Get the active panel for this region.
36601 * @return {Roo.ContentPanel} The active panel or null
36603 getActivePanel : function(){
36604 return this.activePanel;
36607 validateVisibility : function(){
36608 if(this.panels.getCount() < 1){
36609 this.updateTitle(" ");
36610 this.closeBtn.hide();
36613 if(!this.isVisible()){
36620 * Adds the passed ContentPanel(s) to this region.
36621 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36622 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36624 add : function(panel)
36626 if(arguments.length > 1){
36627 for(var i = 0, len = arguments.length; i < len; i++) {
36628 this.add(arguments[i]);
36633 // if we have not been rendered yet, then we can not really do much of this..
36634 if (!this.bodyEl) {
36635 this.unrendered_panels.push(panel);
36642 if(this.hasPanel(panel)){
36643 this.showPanel(panel);
36646 panel.setRegion(this);
36647 this.panels.add(panel);
36648 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36649 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36650 // and hide them... ???
36651 this.bodyEl.dom.appendChild(panel.getEl().dom);
36652 if(panel.background !== true){
36653 this.setActivePanel(panel);
36655 this.fireEvent("paneladded", this, panel);
36662 this.initPanelAsTab(panel);
36666 if(panel.background !== true){
36667 this.tabs.activate(panel.getEl().id);
36669 this.fireEvent("paneladded", this, panel);
36674 * Hides the tab for the specified panel.
36675 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36677 hidePanel : function(panel){
36678 if(this.tabs && (panel = this.getPanel(panel))){
36679 this.tabs.hideTab(panel.getEl().id);
36684 * Unhides the tab for a previously hidden panel.
36685 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36687 unhidePanel : function(panel){
36688 if(this.tabs && (panel = this.getPanel(panel))){
36689 this.tabs.unhideTab(panel.getEl().id);
36693 clearPanels : function(){
36694 while(this.panels.getCount() > 0){
36695 this.remove(this.panels.first());
36700 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36701 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36702 * @param {Boolean} preservePanel Overrides the config preservePanel option
36703 * @return {Roo.ContentPanel} The panel that was removed
36705 remove : function(panel, preservePanel)
36707 panel = this.getPanel(panel);
36712 this.fireEvent("beforeremove", this, panel, e);
36713 if(e.cancel === true){
36716 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36717 var panelId = panel.getId();
36718 this.panels.removeKey(panelId);
36720 document.body.appendChild(panel.getEl().dom);
36723 this.tabs.removeTab(panel.getEl().id);
36724 }else if (!preservePanel){
36725 this.bodyEl.dom.removeChild(panel.getEl().dom);
36727 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36728 var p = this.panels.first();
36729 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36730 tempEl.appendChild(p.getEl().dom);
36731 this.bodyEl.update("");
36732 this.bodyEl.dom.appendChild(p.getEl().dom);
36734 this.updateTitle(p.getTitle());
36736 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36737 this.setActivePanel(p);
36739 panel.setRegion(null);
36740 if(this.activePanel == panel){
36741 this.activePanel = null;
36743 if(this.config.autoDestroy !== false && preservePanel !== true){
36744 try{panel.destroy();}catch(e){}
36746 this.fireEvent("panelremoved", this, panel);
36751 * Returns the TabPanel component used by this region
36752 * @return {Roo.TabPanel}
36754 getTabs : function(){
36758 createTool : function(parentEl, className){
36759 var btn = Roo.DomHelper.append(parentEl, {
36761 cls: "x-layout-tools-button",
36764 cls: "roo-layout-tools-button-inner " + className,
36768 btn.addClassOnOver("roo-layout-tools-button-over");
36773 * Ext JS Library 1.1.1
36774 * Copyright(c) 2006-2007, Ext JS, LLC.
36776 * Originally Released Under LGPL - original licence link has changed is not relivant.
36779 * <script type="text/javascript">
36785 * @class Roo.SplitLayoutRegion
36786 * @extends Roo.LayoutRegion
36787 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36789 Roo.bootstrap.layout.Split = function(config){
36790 this.cursor = config.cursor;
36791 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36794 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36796 splitTip : "Drag to resize.",
36797 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36798 useSplitTips : false,
36800 applyConfig : function(config){
36801 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36804 onRender : function(ctr,pos) {
36806 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36807 if(!this.config.split){
36812 var splitEl = Roo.DomHelper.append(ctr.dom, {
36814 id: this.el.id + "-split",
36815 cls: "roo-layout-split roo-layout-split-"+this.position,
36818 /** The SplitBar for this region
36819 * @type Roo.SplitBar */
36820 // does not exist yet...
36821 Roo.log([this.position, this.orientation]);
36823 this.split = new Roo.bootstrap.SplitBar({
36824 dragElement : splitEl,
36825 resizingElement: this.el,
36826 orientation : this.orientation
36829 this.split.on("moved", this.onSplitMove, this);
36830 this.split.useShim = this.config.useShim === true;
36831 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36832 if(this.useSplitTips){
36833 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36835 //if(config.collapsible){
36836 // this.split.el.on("dblclick", this.collapse, this);
36839 if(typeof this.config.minSize != "undefined"){
36840 this.split.minSize = this.config.minSize;
36842 if(typeof this.config.maxSize != "undefined"){
36843 this.split.maxSize = this.config.maxSize;
36845 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36846 this.hideSplitter();
36851 getHMaxSize : function(){
36852 var cmax = this.config.maxSize || 10000;
36853 var center = this.mgr.getRegion("center");
36854 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36857 getVMaxSize : function(){
36858 var cmax = this.config.maxSize || 10000;
36859 var center = this.mgr.getRegion("center");
36860 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36863 onSplitMove : function(split, newSize){
36864 this.fireEvent("resized", this, newSize);
36868 * Returns the {@link Roo.SplitBar} for this region.
36869 * @return {Roo.SplitBar}
36871 getSplitBar : function(){
36876 this.hideSplitter();
36877 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36880 hideSplitter : function(){
36882 this.split.el.setLocation(-2000,-2000);
36883 this.split.el.hide();
36889 this.split.el.show();
36891 Roo.bootstrap.layout.Split.superclass.show.call(this);
36894 beforeSlide: function(){
36895 if(Roo.isGecko){// firefox overflow auto bug workaround
36896 this.bodyEl.clip();
36898 this.tabs.bodyEl.clip();
36900 if(this.activePanel){
36901 this.activePanel.getEl().clip();
36903 if(this.activePanel.beforeSlide){
36904 this.activePanel.beforeSlide();
36910 afterSlide : function(){
36911 if(Roo.isGecko){// firefox overflow auto bug workaround
36912 this.bodyEl.unclip();
36914 this.tabs.bodyEl.unclip();
36916 if(this.activePanel){
36917 this.activePanel.getEl().unclip();
36918 if(this.activePanel.afterSlide){
36919 this.activePanel.afterSlide();
36925 initAutoHide : function(){
36926 if(this.autoHide !== false){
36927 if(!this.autoHideHd){
36928 var st = new Roo.util.DelayedTask(this.slideIn, this);
36929 this.autoHideHd = {
36930 "mouseout": function(e){
36931 if(!e.within(this.el, true)){
36935 "mouseover" : function(e){
36941 this.el.on(this.autoHideHd);
36945 clearAutoHide : function(){
36946 if(this.autoHide !== false){
36947 this.el.un("mouseout", this.autoHideHd.mouseout);
36948 this.el.un("mouseover", this.autoHideHd.mouseover);
36952 clearMonitor : function(){
36953 Roo.get(document).un("click", this.slideInIf, this);
36956 // these names are backwards but not changed for compat
36957 slideOut : function(){
36958 if(this.isSlid || this.el.hasActiveFx()){
36961 this.isSlid = true;
36962 if(this.collapseBtn){
36963 this.collapseBtn.hide();
36965 this.closeBtnState = this.closeBtn.getStyle('display');
36966 this.closeBtn.hide();
36968 this.stickBtn.show();
36971 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36972 this.beforeSlide();
36973 this.el.setStyle("z-index", 10001);
36974 this.el.slideIn(this.getSlideAnchor(), {
36975 callback: function(){
36977 this.initAutoHide();
36978 Roo.get(document).on("click", this.slideInIf, this);
36979 this.fireEvent("slideshow", this);
36986 afterSlideIn : function(){
36987 this.clearAutoHide();
36988 this.isSlid = false;
36989 this.clearMonitor();
36990 this.el.setStyle("z-index", "");
36991 if(this.collapseBtn){
36992 this.collapseBtn.show();
36994 this.closeBtn.setStyle('display', this.closeBtnState);
36996 this.stickBtn.hide();
36998 this.fireEvent("slidehide", this);
37001 slideIn : function(cb){
37002 if(!this.isSlid || this.el.hasActiveFx()){
37006 this.isSlid = false;
37007 this.beforeSlide();
37008 this.el.slideOut(this.getSlideAnchor(), {
37009 callback: function(){
37010 this.el.setLeftTop(-10000, -10000);
37012 this.afterSlideIn();
37020 slideInIf : function(e){
37021 if(!e.within(this.el)){
37026 animateCollapse : function(){
37027 this.beforeSlide();
37028 this.el.setStyle("z-index", 20000);
37029 var anchor = this.getSlideAnchor();
37030 this.el.slideOut(anchor, {
37031 callback : function(){
37032 this.el.setStyle("z-index", "");
37033 this.collapsedEl.slideIn(anchor, {duration:.3});
37035 this.el.setLocation(-10000,-10000);
37037 this.fireEvent("collapsed", this);
37044 animateExpand : function(){
37045 this.beforeSlide();
37046 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
37047 this.el.setStyle("z-index", 20000);
37048 this.collapsedEl.hide({
37051 this.el.slideIn(this.getSlideAnchor(), {
37052 callback : function(){
37053 this.el.setStyle("z-index", "");
37056 this.split.el.show();
37058 this.fireEvent("invalidated", this);
37059 this.fireEvent("expanded", this);
37087 getAnchor : function(){
37088 return this.anchors[this.position];
37091 getCollapseAnchor : function(){
37092 return this.canchors[this.position];
37095 getSlideAnchor : function(){
37096 return this.sanchors[this.position];
37099 getAlignAdj : function(){
37100 var cm = this.cmargins;
37101 switch(this.position){
37117 getExpandAdj : function(){
37118 var c = this.collapsedEl, cm = this.cmargins;
37119 switch(this.position){
37121 return [-(cm.right+c.getWidth()+cm.left), 0];
37124 return [cm.right+c.getWidth()+cm.left, 0];
37127 return [0, -(cm.top+cm.bottom+c.getHeight())];
37130 return [0, cm.top+cm.bottom+c.getHeight()];
37136 * Ext JS Library 1.1.1
37137 * Copyright(c) 2006-2007, Ext JS, LLC.
37139 * Originally Released Under LGPL - original licence link has changed is not relivant.
37142 * <script type="text/javascript">
37145 * These classes are private internal classes
37147 Roo.bootstrap.layout.Center = function(config){
37148 config.region = "center";
37149 Roo.bootstrap.layout.Region.call(this, config);
37150 this.visible = true;
37151 this.minWidth = config.minWidth || 20;
37152 this.minHeight = config.minHeight || 20;
37155 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37157 // center panel can't be hidden
37161 // center panel can't be hidden
37164 getMinWidth: function(){
37165 return this.minWidth;
37168 getMinHeight: function(){
37169 return this.minHeight;
37183 Roo.bootstrap.layout.North = function(config)
37185 config.region = 'north';
37186 config.cursor = 'n-resize';
37188 Roo.bootstrap.layout.Split.call(this, config);
37192 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37193 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37194 this.split.el.addClass("roo-layout-split-v");
37196 var size = config.initialSize || config.height;
37197 if(typeof size != "undefined"){
37198 this.el.setHeight(size);
37201 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37203 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37207 getBox : function(){
37208 if(this.collapsed){
37209 return this.collapsedEl.getBox();
37211 var box = this.el.getBox();
37213 box.height += this.split.el.getHeight();
37218 updateBox : function(box){
37219 if(this.split && !this.collapsed){
37220 box.height -= this.split.el.getHeight();
37221 this.split.el.setLeft(box.x);
37222 this.split.el.setTop(box.y+box.height);
37223 this.split.el.setWidth(box.width);
37225 if(this.collapsed){
37226 this.updateBody(box.width, null);
37228 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37236 Roo.bootstrap.layout.South = function(config){
37237 config.region = 'south';
37238 config.cursor = 's-resize';
37239 Roo.bootstrap.layout.Split.call(this, config);
37241 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37242 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37243 this.split.el.addClass("roo-layout-split-v");
37245 var size = config.initialSize || config.height;
37246 if(typeof size != "undefined"){
37247 this.el.setHeight(size);
37251 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37252 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37253 getBox : function(){
37254 if(this.collapsed){
37255 return this.collapsedEl.getBox();
37257 var box = this.el.getBox();
37259 var sh = this.split.el.getHeight();
37266 updateBox : function(box){
37267 if(this.split && !this.collapsed){
37268 var sh = this.split.el.getHeight();
37271 this.split.el.setLeft(box.x);
37272 this.split.el.setTop(box.y-sh);
37273 this.split.el.setWidth(box.width);
37275 if(this.collapsed){
37276 this.updateBody(box.width, null);
37278 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37282 Roo.bootstrap.layout.East = function(config){
37283 config.region = "east";
37284 config.cursor = "e-resize";
37285 Roo.bootstrap.layout.Split.call(this, config);
37287 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37288 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37289 this.split.el.addClass("roo-layout-split-h");
37291 var size = config.initialSize || config.width;
37292 if(typeof size != "undefined"){
37293 this.el.setWidth(size);
37296 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37297 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37298 getBox : function(){
37299 if(this.collapsed){
37300 return this.collapsedEl.getBox();
37302 var box = this.el.getBox();
37304 var sw = this.split.el.getWidth();
37311 updateBox : function(box){
37312 if(this.split && !this.collapsed){
37313 var sw = this.split.el.getWidth();
37315 this.split.el.setLeft(box.x);
37316 this.split.el.setTop(box.y);
37317 this.split.el.setHeight(box.height);
37320 if(this.collapsed){
37321 this.updateBody(null, box.height);
37323 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37327 Roo.bootstrap.layout.West = function(config){
37328 config.region = "west";
37329 config.cursor = "w-resize";
37331 Roo.bootstrap.layout.Split.call(this, config);
37333 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37334 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37335 this.split.el.addClass("roo-layout-split-h");
37339 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37340 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37342 onRender: function(ctr, pos)
37344 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37345 var size = this.config.initialSize || this.config.width;
37346 if(typeof size != "undefined"){
37347 this.el.setWidth(size);
37351 getBox : function(){
37352 if(this.collapsed){
37353 return this.collapsedEl.getBox();
37355 var box = this.el.getBox();
37357 box.width += this.split.el.getWidth();
37362 updateBox : function(box){
37363 if(this.split && !this.collapsed){
37364 var sw = this.split.el.getWidth();
37366 this.split.el.setLeft(box.x+box.width);
37367 this.split.el.setTop(box.y);
37368 this.split.el.setHeight(box.height);
37370 if(this.collapsed){
37371 this.updateBody(null, box.height);
37373 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37375 });Roo.namespace("Roo.bootstrap.panel");/*
37377 * Ext JS Library 1.1.1
37378 * Copyright(c) 2006-2007, Ext JS, LLC.
37380 * Originally Released Under LGPL - original licence link has changed is not relivant.
37383 * <script type="text/javascript">
37386 * @class Roo.ContentPanel
37387 * @extends Roo.util.Observable
37388 * A basic ContentPanel element.
37389 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37390 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37391 * @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
37392 * @cfg {Boolean} closable True if the panel can be closed/removed
37393 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37394 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37395 * @cfg {Toolbar} toolbar A toolbar for this panel
37396 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37397 * @cfg {String} title The title for this panel
37398 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37399 * @cfg {String} url Calls {@link #setUrl} with this value
37400 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37401 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37402 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37403 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37404 * @cfg {Boolean} badges render the badges
37407 * Create a new ContentPanel.
37408 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37409 * @param {String/Object} config A string to set only the title or a config object
37410 * @param {String} content (optional) Set the HTML content for this panel
37411 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37413 Roo.bootstrap.panel.Content = function( config){
37415 this.tpl = config.tpl || false;
37417 var el = config.el;
37418 var content = config.content;
37420 if(config.autoCreate){ // xtype is available if this is called from factory
37423 this.el = Roo.get(el);
37424 if(!this.el && config && config.autoCreate){
37425 if(typeof config.autoCreate == "object"){
37426 if(!config.autoCreate.id){
37427 config.autoCreate.id = config.id||el;
37429 this.el = Roo.DomHelper.append(document.body,
37430 config.autoCreate, true);
37432 var elcfg = { tag: "div",
37433 cls: "roo-layout-inactive-content",
37437 elcfg.html = config.html;
37441 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37444 this.closable = false;
37445 this.loaded = false;
37446 this.active = false;
37449 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37451 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37453 this.wrapEl = this.el; //this.el.wrap();
37455 if (config.toolbar.items) {
37456 ti = config.toolbar.items ;
37457 delete config.toolbar.items ;
37461 this.toolbar.render(this.wrapEl, 'before');
37462 for(var i =0;i < ti.length;i++) {
37463 // Roo.log(['add child', items[i]]);
37464 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37466 this.toolbar.items = nitems;
37467 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37468 delete config.toolbar;
37472 // xtype created footer. - not sure if will work as we normally have to render first..
37473 if (this.footer && !this.footer.el && this.footer.xtype) {
37474 if (!this.wrapEl) {
37475 this.wrapEl = this.el.wrap();
37478 this.footer.container = this.wrapEl.createChild();
37480 this.footer = Roo.factory(this.footer, Roo);
37485 if(typeof config == "string"){
37486 this.title = config;
37488 Roo.apply(this, config);
37492 this.resizeEl = Roo.get(this.resizeEl, true);
37494 this.resizeEl = this.el;
37496 // handle view.xtype
37504 * Fires when this panel is activated.
37505 * @param {Roo.ContentPanel} this
37509 * @event deactivate
37510 * Fires when this panel is activated.
37511 * @param {Roo.ContentPanel} this
37513 "deactivate" : true,
37517 * Fires when this panel is resized if fitToFrame is true.
37518 * @param {Roo.ContentPanel} this
37519 * @param {Number} width The width after any component adjustments
37520 * @param {Number} height The height after any component adjustments
37526 * Fires when this tab is created
37527 * @param {Roo.ContentPanel} this
37538 if(this.autoScroll){
37539 this.resizeEl.setStyle("overflow", "auto");
37541 // fix randome scrolling
37542 //this.el.on('scroll', function() {
37543 // Roo.log('fix random scolling');
37544 // this.scrollTo('top',0);
37547 content = content || this.content;
37549 this.setContent(content);
37551 if(config && config.url){
37552 this.setUrl(this.url, this.params, this.loadOnce);
37557 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37559 if (this.view && typeof(this.view.xtype) != 'undefined') {
37560 this.view.el = this.el.appendChild(document.createElement("div"));
37561 this.view = Roo.factory(this.view);
37562 this.view.render && this.view.render(false, '');
37566 this.fireEvent('render', this);
37569 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37573 setRegion : function(region){
37574 this.region = region;
37575 this.setActiveClass(region && !this.background);
37579 setActiveClass: function(state)
37582 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37583 this.el.setStyle('position','relative');
37585 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37586 this.el.setStyle('position', 'absolute');
37591 * Returns the toolbar for this Panel if one was configured.
37592 * @return {Roo.Toolbar}
37594 getToolbar : function(){
37595 return this.toolbar;
37598 setActiveState : function(active)
37600 this.active = active;
37601 this.setActiveClass(active);
37603 if(this.fireEvent("deactivate", this) === false){
37608 this.fireEvent("activate", this);
37612 * Updates this panel's element
37613 * @param {String} content The new content
37614 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37616 setContent : function(content, loadScripts){
37617 this.el.update(content, loadScripts);
37620 ignoreResize : function(w, h){
37621 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37624 this.lastSize = {width: w, height: h};
37629 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37630 * @return {Roo.UpdateManager} The UpdateManager
37632 getUpdateManager : function(){
37633 return this.el.getUpdateManager();
37636 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37637 * @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:
37640 url: "your-url.php",
37641 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37642 callback: yourFunction,
37643 scope: yourObject, //(optional scope)
37646 text: "Loading...",
37651 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37652 * 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.
37653 * @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}
37654 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37655 * @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.
37656 * @return {Roo.ContentPanel} this
37659 var um = this.el.getUpdateManager();
37660 um.update.apply(um, arguments);
37666 * 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.
37667 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37668 * @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)
37669 * @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)
37670 * @return {Roo.UpdateManager} The UpdateManager
37672 setUrl : function(url, params, loadOnce){
37673 if(this.refreshDelegate){
37674 this.removeListener("activate", this.refreshDelegate);
37676 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37677 this.on("activate", this.refreshDelegate);
37678 return this.el.getUpdateManager();
37681 _handleRefresh : function(url, params, loadOnce){
37682 if(!loadOnce || !this.loaded){
37683 var updater = this.el.getUpdateManager();
37684 updater.update(url, params, this._setLoaded.createDelegate(this));
37688 _setLoaded : function(){
37689 this.loaded = true;
37693 * Returns this panel's id
37696 getId : function(){
37701 * Returns this panel's element - used by regiosn to add.
37702 * @return {Roo.Element}
37704 getEl : function(){
37705 return this.wrapEl || this.el;
37710 adjustForComponents : function(width, height)
37712 //Roo.log('adjustForComponents ');
37713 if(this.resizeEl != this.el){
37714 width -= this.el.getFrameWidth('lr');
37715 height -= this.el.getFrameWidth('tb');
37718 var te = this.toolbar.getEl();
37719 te.setWidth(width);
37720 height -= te.getHeight();
37723 var te = this.footer.getEl();
37724 te.setWidth(width);
37725 height -= te.getHeight();
37729 if(this.adjustments){
37730 width += this.adjustments[0];
37731 height += this.adjustments[1];
37733 return {"width": width, "height": height};
37736 setSize : function(width, height){
37737 if(this.fitToFrame && !this.ignoreResize(width, height)){
37738 if(this.fitContainer && this.resizeEl != this.el){
37739 this.el.setSize(width, height);
37741 var size = this.adjustForComponents(width, height);
37742 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37743 this.fireEvent('resize', this, size.width, size.height);
37748 * Returns this panel's title
37751 getTitle : function(){
37753 if (typeof(this.title) != 'object') {
37758 for (var k in this.title) {
37759 if (!this.title.hasOwnProperty(k)) {
37763 if (k.indexOf('-') >= 0) {
37764 var s = k.split('-');
37765 for (var i = 0; i<s.length; i++) {
37766 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37769 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37776 * Set this panel's title
37777 * @param {String} title
37779 setTitle : function(title){
37780 this.title = title;
37782 this.region.updatePanelTitle(this, title);
37787 * Returns true is this panel was configured to be closable
37788 * @return {Boolean}
37790 isClosable : function(){
37791 return this.closable;
37794 beforeSlide : function(){
37796 this.resizeEl.clip();
37799 afterSlide : function(){
37801 this.resizeEl.unclip();
37805 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37806 * Will fail silently if the {@link #setUrl} method has not been called.
37807 * This does not activate the panel, just updates its content.
37809 refresh : function(){
37810 if(this.refreshDelegate){
37811 this.loaded = false;
37812 this.refreshDelegate();
37817 * Destroys this panel
37819 destroy : function(){
37820 this.el.removeAllListeners();
37821 var tempEl = document.createElement("span");
37822 tempEl.appendChild(this.el.dom);
37823 tempEl.innerHTML = "";
37829 * form - if the content panel contains a form - this is a reference to it.
37830 * @type {Roo.form.Form}
37834 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37835 * This contains a reference to it.
37841 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37851 * @param {Object} cfg Xtype definition of item to add.
37855 getChildContainer: function () {
37856 return this.getEl();
37861 var ret = new Roo.factory(cfg);
37866 if (cfg.xtype.match(/^Form$/)) {
37869 //if (this.footer) {
37870 // el = this.footer.container.insertSibling(false, 'before');
37872 el = this.el.createChild();
37875 this.form = new Roo.form.Form(cfg);
37878 if ( this.form.allItems.length) {
37879 this.form.render(el.dom);
37883 // should only have one of theses..
37884 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37885 // views.. should not be just added - used named prop 'view''
37887 cfg.el = this.el.appendChild(document.createElement("div"));
37890 var ret = new Roo.factory(cfg);
37892 ret.render && ret.render(false, ''); // render blank..
37902 * @class Roo.bootstrap.panel.Grid
37903 * @extends Roo.bootstrap.panel.Content
37905 * Create a new GridPanel.
37906 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37907 * @param {Object} config A the config object
37913 Roo.bootstrap.panel.Grid = function(config)
37917 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37918 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37920 config.el = this.wrapper;
37921 //this.el = this.wrapper;
37923 if (config.container) {
37924 // ctor'ed from a Border/panel.grid
37927 this.wrapper.setStyle("overflow", "hidden");
37928 this.wrapper.addClass('roo-grid-container');
37933 if(config.toolbar){
37934 var tool_el = this.wrapper.createChild();
37935 this.toolbar = Roo.factory(config.toolbar);
37937 if (config.toolbar.items) {
37938 ti = config.toolbar.items ;
37939 delete config.toolbar.items ;
37943 this.toolbar.render(tool_el);
37944 for(var i =0;i < ti.length;i++) {
37945 // Roo.log(['add child', items[i]]);
37946 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37948 this.toolbar.items = nitems;
37950 delete config.toolbar;
37953 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37954 config.grid.scrollBody = true;;
37955 config.grid.monitorWindowResize = false; // turn off autosizing
37956 config.grid.autoHeight = false;
37957 config.grid.autoWidth = false;
37959 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37961 if (config.background) {
37962 // render grid on panel activation (if panel background)
37963 this.on('activate', function(gp) {
37964 if (!gp.grid.rendered) {
37965 gp.grid.render(this.wrapper);
37966 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37971 this.grid.render(this.wrapper);
37972 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37975 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37976 // ??? needed ??? config.el = this.wrapper;
37981 // xtype created footer. - not sure if will work as we normally have to render first..
37982 if (this.footer && !this.footer.el && this.footer.xtype) {
37984 var ctr = this.grid.getView().getFooterPanel(true);
37985 this.footer.dataSource = this.grid.dataSource;
37986 this.footer = Roo.factory(this.footer, Roo);
37987 this.footer.render(ctr);
37997 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37998 getId : function(){
37999 return this.grid.id;
38003 * Returns the grid for this panel
38004 * @return {Roo.bootstrap.Table}
38006 getGrid : function(){
38010 setSize : function(width, height){
38011 if(!this.ignoreResize(width, height)){
38012 var grid = this.grid;
38013 var size = this.adjustForComponents(width, height);
38014 var gridel = grid.getGridEl();
38015 gridel.setSize(size.width, size.height);
38017 var thd = grid.getGridEl().select('thead',true).first();
38018 var tbd = grid.getGridEl().select('tbody', true).first();
38020 tbd.setSize(width, height - thd.getHeight());
38029 beforeSlide : function(){
38030 this.grid.getView().scroller.clip();
38033 afterSlide : function(){
38034 this.grid.getView().scroller.unclip();
38037 destroy : function(){
38038 this.grid.destroy();
38040 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
38045 * @class Roo.bootstrap.panel.Nest
38046 * @extends Roo.bootstrap.panel.Content
38048 * Create a new Panel, that can contain a layout.Border.
38051 * @param {Roo.BorderLayout} layout The layout for this panel
38052 * @param {String/Object} config A string to set only the title or a config object
38054 Roo.bootstrap.panel.Nest = function(config)
38056 // construct with only one argument..
38057 /* FIXME - implement nicer consturctors
38058 if (layout.layout) {
38060 layout = config.layout;
38061 delete config.layout;
38063 if (layout.xtype && !layout.getEl) {
38064 // then layout needs constructing..
38065 layout = Roo.factory(layout, Roo);
38069 config.el = config.layout.getEl();
38071 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38073 config.layout.monitorWindowResize = false; // turn off autosizing
38074 this.layout = config.layout;
38075 this.layout.getEl().addClass("roo-layout-nested-layout");
38076 this.layout.parent = this;
38083 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38085 setSize : function(width, height){
38086 if(!this.ignoreResize(width, height)){
38087 var size = this.adjustForComponents(width, height);
38088 var el = this.layout.getEl();
38089 if (size.height < 1) {
38090 el.setWidth(size.width);
38092 el.setSize(size.width, size.height);
38094 var touch = el.dom.offsetWidth;
38095 this.layout.layout();
38096 // ie requires a double layout on the first pass
38097 if(Roo.isIE && !this.initialized){
38098 this.initialized = true;
38099 this.layout.layout();
38104 // activate all subpanels if not currently active..
38106 setActiveState : function(active){
38107 this.active = active;
38108 this.setActiveClass(active);
38111 this.fireEvent("deactivate", this);
38115 this.fireEvent("activate", this);
38116 // not sure if this should happen before or after..
38117 if (!this.layout) {
38118 return; // should not happen..
38121 for (var r in this.layout.regions) {
38122 reg = this.layout.getRegion(r);
38123 if (reg.getActivePanel()) {
38124 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38125 reg.setActivePanel(reg.getActivePanel());
38128 if (!reg.panels.length) {
38131 reg.showPanel(reg.getPanel(0));
38140 * Returns the nested BorderLayout for this panel
38141 * @return {Roo.BorderLayout}
38143 getLayout : function(){
38144 return this.layout;
38148 * Adds a xtype elements to the layout of the nested panel
38152 xtype : 'ContentPanel',
38159 xtype : 'NestedLayoutPanel',
38165 items : [ ... list of content panels or nested layout panels.. ]
38169 * @param {Object} cfg Xtype definition of item to add.
38171 addxtype : function(cfg) {
38172 return this.layout.addxtype(cfg);
38177 * Ext JS Library 1.1.1
38178 * Copyright(c) 2006-2007, Ext JS, LLC.
38180 * Originally Released Under LGPL - original licence link has changed is not relivant.
38183 * <script type="text/javascript">
38186 * @class Roo.TabPanel
38187 * @extends Roo.util.Observable
38188 * A lightweight tab container.
38192 // basic tabs 1, built from existing content
38193 var tabs = new Roo.TabPanel("tabs1");
38194 tabs.addTab("script", "View Script");
38195 tabs.addTab("markup", "View Markup");
38196 tabs.activate("script");
38198 // more advanced tabs, built from javascript
38199 var jtabs = new Roo.TabPanel("jtabs");
38200 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38202 // set up the UpdateManager
38203 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38204 var updater = tab2.getUpdateManager();
38205 updater.setDefaultUrl("ajax1.htm");
38206 tab2.on('activate', updater.refresh, updater, true);
38208 // Use setUrl for Ajax loading
38209 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38210 tab3.setUrl("ajax2.htm", null, true);
38213 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38216 jtabs.activate("jtabs-1");
38219 * Create a new TabPanel.
38220 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38221 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38223 Roo.bootstrap.panel.Tabs = function(config){
38225 * The container element for this TabPanel.
38226 * @type Roo.Element
38228 this.el = Roo.get(config.el);
38231 if(typeof config == "boolean"){
38232 this.tabPosition = config ? "bottom" : "top";
38234 Roo.apply(this, config);
38238 if(this.tabPosition == "bottom"){
38239 // if tabs are at the bottom = create the body first.
38240 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38241 this.el.addClass("roo-tabs-bottom");
38243 // next create the tabs holders
38245 if (this.tabPosition == "west"){
38247 var reg = this.region; // fake it..
38249 if (!reg.mgr.parent) {
38252 reg = reg.mgr.parent.region;
38254 Roo.log("got nest?");
38256 if (reg.mgr.getRegion('west')) {
38257 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38258 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38259 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38260 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38261 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38269 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38270 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38271 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38272 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38277 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38280 // finally - if tabs are at the top, then create the body last..
38281 if(this.tabPosition != "bottom"){
38282 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38283 * @type Roo.Element
38285 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38286 this.el.addClass("roo-tabs-top");
38290 this.bodyEl.setStyle("position", "relative");
38292 this.active = null;
38293 this.activateDelegate = this.activate.createDelegate(this);
38298 * Fires when the active tab changes
38299 * @param {Roo.TabPanel} this
38300 * @param {Roo.TabPanelItem} activePanel The new active tab
38304 * @event beforetabchange
38305 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38306 * @param {Roo.TabPanel} this
38307 * @param {Object} e Set cancel to true on this object to cancel the tab change
38308 * @param {Roo.TabPanelItem} tab The tab being changed to
38310 "beforetabchange" : true
38313 Roo.EventManager.onWindowResize(this.onResize, this);
38314 this.cpad = this.el.getPadding("lr");
38315 this.hiddenCount = 0;
38318 // toolbar on the tabbar support...
38319 if (this.toolbar) {
38320 alert("no toolbar support yet");
38321 this.toolbar = false;
38323 var tcfg = this.toolbar;
38324 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38325 this.toolbar = new Roo.Toolbar(tcfg);
38326 if (Roo.isSafari) {
38327 var tbl = tcfg.container.child('table', true);
38328 tbl.setAttribute('width', '100%');
38336 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38339 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38341 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38343 tabPosition : "top",
38345 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38347 currentTabWidth : 0,
38349 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38353 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38357 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38359 preferredTabWidth : 175,
38361 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38363 resizeTabs : false,
38365 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38367 monitorResize : true,
38369 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38371 toolbar : false, // set by caller..
38373 region : false, /// set by caller
38375 disableTooltips : true, // not used yet...
38378 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38379 * @param {String} id The id of the div to use <b>or create</b>
38380 * @param {String} text The text for the tab
38381 * @param {String} content (optional) Content to put in the TabPanelItem body
38382 * @param {Boolean} closable (optional) True to create a close icon on the tab
38383 * @return {Roo.TabPanelItem} The created TabPanelItem
38385 addTab : function(id, text, content, closable, tpl)
38387 var item = new Roo.bootstrap.panel.TabItem({
38391 closable : closable,
38394 this.addTabItem(item);
38396 item.setContent(content);
38402 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38403 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38404 * @return {Roo.TabPanelItem}
38406 getTab : function(id){
38407 return this.items[id];
38411 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38412 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38414 hideTab : function(id){
38415 var t = this.items[id];
38418 this.hiddenCount++;
38419 this.autoSizeTabs();
38424 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38425 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38427 unhideTab : function(id){
38428 var t = this.items[id];
38430 t.setHidden(false);
38431 this.hiddenCount--;
38432 this.autoSizeTabs();
38437 * Adds an existing {@link Roo.TabPanelItem}.
38438 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38440 addTabItem : function(item)
38442 this.items[item.id] = item;
38443 this.items.push(item);
38444 this.autoSizeTabs();
38445 // if(this.resizeTabs){
38446 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38447 // this.autoSizeTabs();
38449 // item.autoSize();
38454 * Removes a {@link Roo.TabPanelItem}.
38455 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38457 removeTab : function(id){
38458 var items = this.items;
38459 var tab = items[id];
38460 if(!tab) { return; }
38461 var index = items.indexOf(tab);
38462 if(this.active == tab && items.length > 1){
38463 var newTab = this.getNextAvailable(index);
38468 this.stripEl.dom.removeChild(tab.pnode.dom);
38469 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38470 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38472 items.splice(index, 1);
38473 delete this.items[tab.id];
38474 tab.fireEvent("close", tab);
38475 tab.purgeListeners();
38476 this.autoSizeTabs();
38479 getNextAvailable : function(start){
38480 var items = this.items;
38482 // look for a next tab that will slide over to
38483 // replace the one being removed
38484 while(index < items.length){
38485 var item = items[++index];
38486 if(item && !item.isHidden()){
38490 // if one isn't found select the previous tab (on the left)
38493 var item = items[--index];
38494 if(item && !item.isHidden()){
38502 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38503 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38505 disableTab : function(id){
38506 var tab = this.items[id];
38507 if(tab && this.active != tab){
38513 * Enables a {@link Roo.TabPanelItem} that is disabled.
38514 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38516 enableTab : function(id){
38517 var tab = this.items[id];
38522 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38523 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38524 * @return {Roo.TabPanelItem} The TabPanelItem.
38526 activate : function(id)
38528 //Roo.log('activite:' + id);
38530 var tab = this.items[id];
38534 if(tab == this.active || tab.disabled){
38538 this.fireEvent("beforetabchange", this, e, tab);
38539 if(e.cancel !== true && !tab.disabled){
38541 this.active.hide();
38543 this.active = this.items[id];
38544 this.active.show();
38545 this.fireEvent("tabchange", this, this.active);
38551 * Gets the active {@link Roo.TabPanelItem}.
38552 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38554 getActiveTab : function(){
38555 return this.active;
38559 * Updates the tab body element to fit the height of the container element
38560 * for overflow scrolling
38561 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38563 syncHeight : function(targetHeight){
38564 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38565 var bm = this.bodyEl.getMargins();
38566 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38567 this.bodyEl.setHeight(newHeight);
38571 onResize : function(){
38572 if(this.monitorResize){
38573 this.autoSizeTabs();
38578 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38580 beginUpdate : function(){
38581 this.updating = true;
38585 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38587 endUpdate : function(){
38588 this.updating = false;
38589 this.autoSizeTabs();
38593 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38595 autoSizeTabs : function()
38597 var count = this.items.length;
38598 var vcount = count - this.hiddenCount;
38601 this.stripEl.hide();
38603 this.stripEl.show();
38606 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38611 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38612 var availWidth = Math.floor(w / vcount);
38613 var b = this.stripBody;
38614 if(b.getWidth() > w){
38615 var tabs = this.items;
38616 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38617 if(availWidth < this.minTabWidth){
38618 /*if(!this.sleft){ // incomplete scrolling code
38619 this.createScrollButtons();
38622 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38625 if(this.currentTabWidth < this.preferredTabWidth){
38626 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38632 * Returns the number of tabs in this TabPanel.
38635 getCount : function(){
38636 return this.items.length;
38640 * Resizes all the tabs to the passed width
38641 * @param {Number} The new width
38643 setTabWidth : function(width){
38644 this.currentTabWidth = width;
38645 for(var i = 0, len = this.items.length; i < len; i++) {
38646 if(!this.items[i].isHidden()) {
38647 this.items[i].setWidth(width);
38653 * Destroys this TabPanel
38654 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38656 destroy : function(removeEl){
38657 Roo.EventManager.removeResizeListener(this.onResize, this);
38658 for(var i = 0, len = this.items.length; i < len; i++){
38659 this.items[i].purgeListeners();
38661 if(removeEl === true){
38662 this.el.update("");
38667 createStrip : function(container)
38669 var strip = document.createElement("nav");
38670 strip.className = Roo.bootstrap.version == 4 ?
38671 "navbar-light bg-light" :
38672 "navbar navbar-default"; //"x-tabs-wrap";
38673 container.appendChild(strip);
38677 createStripList : function(strip)
38679 // div wrapper for retard IE
38680 // returns the "tr" element.
38681 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38682 //'<div class="x-tabs-strip-wrap">'+
38683 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38684 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38685 return strip.firstChild; //.firstChild.firstChild.firstChild;
38687 createBody : function(container)
38689 var body = document.createElement("div");
38690 Roo.id(body, "tab-body");
38691 //Roo.fly(body).addClass("x-tabs-body");
38692 Roo.fly(body).addClass("tab-content");
38693 container.appendChild(body);
38696 createItemBody :function(bodyEl, id){
38697 var body = Roo.getDom(id);
38699 body = document.createElement("div");
38702 //Roo.fly(body).addClass("x-tabs-item-body");
38703 Roo.fly(body).addClass("tab-pane");
38704 bodyEl.insertBefore(body, bodyEl.firstChild);
38708 createStripElements : function(stripEl, text, closable, tpl)
38710 var td = document.createElement("li"); // was td..
38711 td.className = 'nav-item';
38713 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38716 stripEl.appendChild(td);
38718 td.className = "x-tabs-closable";
38719 if(!this.closeTpl){
38720 this.closeTpl = new Roo.Template(
38721 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38722 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38723 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38726 var el = this.closeTpl.overwrite(td, {"text": text});
38727 var close = el.getElementsByTagName("div")[0];
38728 var inner = el.getElementsByTagName("em")[0];
38729 return {"el": el, "close": close, "inner": inner};
38732 // not sure what this is..
38733 // if(!this.tabTpl){
38734 //this.tabTpl = new Roo.Template(
38735 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38736 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38738 // this.tabTpl = new Roo.Template(
38739 // '<a href="#">' +
38740 // '<span unselectable="on"' +
38741 // (this.disableTooltips ? '' : ' title="{text}"') +
38742 // ' >{text}</span></a>'
38748 var template = tpl || this.tabTpl || false;
38751 template = new Roo.Template(
38752 Roo.bootstrap.version == 4 ?
38754 '<a class="nav-link" href="#" unselectable="on"' +
38755 (this.disableTooltips ? '' : ' title="{text}"') +
38758 '<a class="nav-link" href="#">' +
38759 '<span unselectable="on"' +
38760 (this.disableTooltips ? '' : ' title="{text}"') +
38761 ' >{text}</span></a>'
38766 switch (typeof(template)) {
38770 template = new Roo.Template(template);
38776 var el = template.overwrite(td, {"text": text});
38778 var inner = el.getElementsByTagName("span")[0];
38780 return {"el": el, "inner": inner};
38788 * @class Roo.TabPanelItem
38789 * @extends Roo.util.Observable
38790 * Represents an individual item (tab plus body) in a TabPanel.
38791 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38792 * @param {String} id The id of this TabPanelItem
38793 * @param {String} text The text for the tab of this TabPanelItem
38794 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38796 Roo.bootstrap.panel.TabItem = function(config){
38798 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38799 * @type Roo.TabPanel
38801 this.tabPanel = config.panel;
38803 * The id for this TabPanelItem
38806 this.id = config.id;
38808 this.disabled = false;
38810 this.text = config.text;
38812 this.loaded = false;
38813 this.closable = config.closable;
38816 * The body element for this TabPanelItem.
38817 * @type Roo.Element
38819 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38820 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38821 this.bodyEl.setStyle("display", "block");
38822 this.bodyEl.setStyle("zoom", "1");
38823 //this.hideAction();
38825 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38827 this.el = Roo.get(els.el);
38828 this.inner = Roo.get(els.inner, true);
38829 this.textEl = Roo.bootstrap.version == 4 ?
38830 this.el : Roo.get(this.el.dom.firstChild, true);
38832 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38833 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38836 // this.el.on("mousedown", this.onTabMouseDown, this);
38837 this.el.on("click", this.onTabClick, this);
38839 if(config.closable){
38840 var c = Roo.get(els.close, true);
38841 c.dom.title = this.closeText;
38842 c.addClassOnOver("close-over");
38843 c.on("click", this.closeClick, this);
38849 * Fires when this tab becomes the active tab.
38850 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38851 * @param {Roo.TabPanelItem} this
38855 * @event beforeclose
38856 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38857 * @param {Roo.TabPanelItem} this
38858 * @param {Object} e Set cancel to true on this object to cancel the close.
38860 "beforeclose": true,
38863 * Fires when this tab is closed.
38864 * @param {Roo.TabPanelItem} this
38868 * @event deactivate
38869 * Fires when this tab is no longer the active tab.
38870 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38871 * @param {Roo.TabPanelItem} this
38873 "deactivate" : true
38875 this.hidden = false;
38877 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38880 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38882 purgeListeners : function(){
38883 Roo.util.Observable.prototype.purgeListeners.call(this);
38884 this.el.removeAllListeners();
38887 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38890 this.status_node.addClass("active");
38893 this.tabPanel.stripWrap.repaint();
38895 this.fireEvent("activate", this.tabPanel, this);
38899 * Returns true if this tab is the active tab.
38900 * @return {Boolean}
38902 isActive : function(){
38903 return this.tabPanel.getActiveTab() == this;
38907 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38910 this.status_node.removeClass("active");
38912 this.fireEvent("deactivate", this.tabPanel, this);
38915 hideAction : function(){
38916 this.bodyEl.hide();
38917 this.bodyEl.setStyle("position", "absolute");
38918 this.bodyEl.setLeft("-20000px");
38919 this.bodyEl.setTop("-20000px");
38922 showAction : function(){
38923 this.bodyEl.setStyle("position", "relative");
38924 this.bodyEl.setTop("");
38925 this.bodyEl.setLeft("");
38926 this.bodyEl.show();
38930 * Set the tooltip for the tab.
38931 * @param {String} tooltip The tab's tooltip
38933 setTooltip : function(text){
38934 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38935 this.textEl.dom.qtip = text;
38936 this.textEl.dom.removeAttribute('title');
38938 this.textEl.dom.title = text;
38942 onTabClick : function(e){
38943 e.preventDefault();
38944 this.tabPanel.activate(this.id);
38947 onTabMouseDown : function(e){
38948 e.preventDefault();
38949 this.tabPanel.activate(this.id);
38952 getWidth : function(){
38953 return this.inner.getWidth();
38956 setWidth : function(width){
38957 var iwidth = width - this.linode.getPadding("lr");
38958 this.inner.setWidth(iwidth);
38959 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38960 this.linode.setWidth(width);
38964 * Show or hide the tab
38965 * @param {Boolean} hidden True to hide or false to show.
38967 setHidden : function(hidden){
38968 this.hidden = hidden;
38969 this.linode.setStyle("display", hidden ? "none" : "");
38973 * Returns true if this tab is "hidden"
38974 * @return {Boolean}
38976 isHidden : function(){
38977 return this.hidden;
38981 * Returns the text for this tab
38984 getText : function(){
38988 autoSize : function(){
38989 //this.el.beginMeasure();
38990 this.textEl.setWidth(1);
38992 * #2804 [new] Tabs in Roojs
38993 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38995 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38996 //this.el.endMeasure();
39000 * Sets the text for the tab (Note: this also sets the tooltip text)
39001 * @param {String} text The tab's text and tooltip
39003 setText : function(text){
39005 this.textEl.update(text);
39006 this.setTooltip(text);
39007 //if(!this.tabPanel.resizeTabs){
39008 // this.autoSize();
39012 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
39014 activate : function(){
39015 this.tabPanel.activate(this.id);
39019 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
39021 disable : function(){
39022 if(this.tabPanel.active != this){
39023 this.disabled = true;
39024 this.status_node.addClass("disabled");
39029 * Enables this TabPanelItem if it was previously disabled.
39031 enable : function(){
39032 this.disabled = false;
39033 this.status_node.removeClass("disabled");
39037 * Sets the content for this TabPanelItem.
39038 * @param {String} content The content
39039 * @param {Boolean} loadScripts true to look for and load scripts
39041 setContent : function(content, loadScripts){
39042 this.bodyEl.update(content, loadScripts);
39046 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
39047 * @return {Roo.UpdateManager} The UpdateManager
39049 getUpdateManager : function(){
39050 return this.bodyEl.getUpdateManager();
39054 * Set a URL to be used to load the content for this TabPanelItem.
39055 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
39056 * @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)
39057 * @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)
39058 * @return {Roo.UpdateManager} The UpdateManager
39060 setUrl : function(url, params, loadOnce){
39061 if(this.refreshDelegate){
39062 this.un('activate', this.refreshDelegate);
39064 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39065 this.on("activate", this.refreshDelegate);
39066 return this.bodyEl.getUpdateManager();
39070 _handleRefresh : function(url, params, loadOnce){
39071 if(!loadOnce || !this.loaded){
39072 var updater = this.bodyEl.getUpdateManager();
39073 updater.update(url, params, this._setLoaded.createDelegate(this));
39078 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39079 * Will fail silently if the setUrl method has not been called.
39080 * This does not activate the panel, just updates its content.
39082 refresh : function(){
39083 if(this.refreshDelegate){
39084 this.loaded = false;
39085 this.refreshDelegate();
39090 _setLoaded : function(){
39091 this.loaded = true;
39095 closeClick : function(e){
39098 this.fireEvent("beforeclose", this, o);
39099 if(o.cancel !== true){
39100 this.tabPanel.removeTab(this.id);
39104 * The text displayed in the tooltip for the close icon.
39107 closeText : "Close this tab"
39110 * This script refer to:
39111 * Title: International Telephone Input
39112 * Author: Jack O'Connor
39113 * Code version: v12.1.12
39114 * Availability: https://github.com/jackocnr/intl-tel-input.git
39117 Roo.bootstrap.PhoneInputData = function() {
39120 "Afghanistan (افغانستان)",
39125 "Albania (Shqipëri)",
39130 "Algeria (الجزائر)",
39155 "Antigua and Barbuda",
39165 "Armenia (Հայաստան)",
39181 "Austria (Österreich)",
39186 "Azerbaijan (Azərbaycan)",
39196 "Bahrain (البحرين)",
39201 "Bangladesh (বাংলাদেশ)",
39211 "Belarus (Беларусь)",
39216 "Belgium (België)",
39246 "Bosnia and Herzegovina (Босна и Херцеговина)",
39261 "British Indian Ocean Territory",
39266 "British Virgin Islands",
39276 "Bulgaria (България)",
39286 "Burundi (Uburundi)",
39291 "Cambodia (កម្ពុជា)",
39296 "Cameroon (Cameroun)",
39305 ["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"]
39308 "Cape Verde (Kabu Verdi)",
39313 "Caribbean Netherlands",
39324 "Central African Republic (République centrafricaine)",
39344 "Christmas Island",
39350 "Cocos (Keeling) Islands",
39361 "Comoros (جزر القمر)",
39366 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39371 "Congo (Republic) (Congo-Brazzaville)",
39391 "Croatia (Hrvatska)",
39412 "Czech Republic (Česká republika)",
39417 "Denmark (Danmark)",
39432 "Dominican Republic (República Dominicana)",
39436 ["809", "829", "849"]
39454 "Equatorial Guinea (Guinea Ecuatorial)",
39474 "Falkland Islands (Islas Malvinas)",
39479 "Faroe Islands (Føroyar)",
39500 "French Guiana (Guyane française)",
39505 "French Polynesia (Polynésie française)",
39520 "Georgia (საქართველო)",
39525 "Germany (Deutschland)",
39545 "Greenland (Kalaallit Nunaat)",
39582 "Guinea-Bissau (Guiné Bissau)",
39607 "Hungary (Magyarország)",
39612 "Iceland (Ísland)",
39632 "Iraq (العراق)",
39648 "Israel (ישראל)",
39675 "Jordan (الأردن)",
39680 "Kazakhstan (Казахстан)",
39701 "Kuwait (الكويت)",
39706 "Kyrgyzstan (Кыргызстан)",
39716 "Latvia (Latvija)",
39721 "Lebanon (لبنان)",
39736 "Libya (ليبيا)",
39746 "Lithuania (Lietuva)",
39761 "Macedonia (FYROM) (Македонија)",
39766 "Madagascar (Madagasikara)",
39796 "Marshall Islands",
39806 "Mauritania (موريتانيا)",
39811 "Mauritius (Moris)",
39832 "Moldova (Republica Moldova)",
39842 "Mongolia (Монгол)",
39847 "Montenegro (Crna Gora)",
39857 "Morocco (المغرب)",
39863 "Mozambique (Moçambique)",
39868 "Myanmar (Burma) (မြန်မာ)",
39873 "Namibia (Namibië)",
39888 "Netherlands (Nederland)",
39893 "New Caledonia (Nouvelle-Calédonie)",
39928 "North Korea (조선 민주주의 인민 공화국)",
39933 "Northern Mariana Islands",
39949 "Pakistan (پاکستان)",
39959 "Palestine (فلسطين)",
39969 "Papua New Guinea",
40011 "Réunion (La Réunion)",
40017 "Romania (România)",
40033 "Saint Barthélemy",
40044 "Saint Kitts and Nevis",
40054 "Saint Martin (Saint-Martin (partie française))",
40060 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
40065 "Saint Vincent and the Grenadines",
40080 "São Tomé and Príncipe (São Tomé e Príncipe)",
40085 "Saudi Arabia (المملكة العربية السعودية)",
40090 "Senegal (Sénégal)",
40120 "Slovakia (Slovensko)",
40125 "Slovenia (Slovenija)",
40135 "Somalia (Soomaaliya)",
40145 "South Korea (대한민국)",
40150 "South Sudan (جنوب السودان)",
40160 "Sri Lanka (ශ්රී ලංකාව)",
40165 "Sudan (السودان)",
40175 "Svalbard and Jan Mayen",
40186 "Sweden (Sverige)",
40191 "Switzerland (Schweiz)",
40196 "Syria (سوريا)",
40241 "Trinidad and Tobago",
40246 "Tunisia (تونس)",
40251 "Turkey (Türkiye)",
40261 "Turks and Caicos Islands",
40271 "U.S. Virgin Islands",
40281 "Ukraine (Україна)",
40286 "United Arab Emirates (الإمارات العربية المتحدة)",
40308 "Uzbekistan (Oʻzbekiston)",
40318 "Vatican City (Città del Vaticano)",
40329 "Vietnam (Việt Nam)",
40334 "Wallis and Futuna (Wallis-et-Futuna)",
40339 "Western Sahara (الصحراء الغربية)",
40345 "Yemen (اليمن)",
40369 * This script refer to:
40370 * Title: International Telephone Input
40371 * Author: Jack O'Connor
40372 * Code version: v12.1.12
40373 * Availability: https://github.com/jackocnr/intl-tel-input.git
40377 * @class Roo.bootstrap.PhoneInput
40378 * @extends Roo.bootstrap.TriggerField
40379 * An input with International dial-code selection
40381 * @cfg {String} defaultDialCode default '+852'
40382 * @cfg {Array} preferedCountries default []
40385 * Create a new PhoneInput.
40386 * @param {Object} config Configuration options
40389 Roo.bootstrap.PhoneInput = function(config) {
40390 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40393 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40395 listWidth: undefined,
40397 selectedClass: 'active',
40399 invalidClass : "has-warning",
40401 validClass: 'has-success',
40403 allowed: '0123456789',
40408 * @cfg {String} defaultDialCode The default dial code when initializing the input
40410 defaultDialCode: '+852',
40413 * @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
40415 preferedCountries: false,
40417 getAutoCreate : function()
40419 var data = Roo.bootstrap.PhoneInputData();
40420 var align = this.labelAlign || this.parentLabelAlign();
40423 this.allCountries = [];
40424 this.dialCodeMapping = [];
40426 for (var i = 0; i < data.length; i++) {
40428 this.allCountries[i] = {
40432 priority: c[3] || 0,
40433 areaCodes: c[4] || null
40435 this.dialCodeMapping[c[2]] = {
40438 priority: c[3] || 0,
40439 areaCodes: c[4] || null
40451 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40452 maxlength: this.max_length,
40453 cls : 'form-control tel-input',
40454 autocomplete: 'new-password'
40457 var hiddenInput = {
40460 cls: 'hidden-tel-input'
40464 hiddenInput.name = this.name;
40467 if (this.disabled) {
40468 input.disabled = true;
40471 var flag_container = {
40488 cls: this.hasFeedback ? 'has-feedback' : '',
40494 cls: 'dial-code-holder',
40501 cls: 'roo-select2-container input-group',
40508 if (this.fieldLabel.length) {
40511 tooltip: 'This field is required'
40517 cls: 'control-label',
40523 html: this.fieldLabel
40526 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40532 if(this.indicatorpos == 'right') {
40533 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40540 if(align == 'left') {
40548 if(this.labelWidth > 12){
40549 label.style = "width: " + this.labelWidth + 'px';
40551 if(this.labelWidth < 13 && this.labelmd == 0){
40552 this.labelmd = this.labelWidth;
40554 if(this.labellg > 0){
40555 label.cls += ' col-lg-' + this.labellg;
40556 input.cls += ' col-lg-' + (12 - this.labellg);
40558 if(this.labelmd > 0){
40559 label.cls += ' col-md-' + this.labelmd;
40560 container.cls += ' col-md-' + (12 - this.labelmd);
40562 if(this.labelsm > 0){
40563 label.cls += ' col-sm-' + this.labelsm;
40564 container.cls += ' col-sm-' + (12 - this.labelsm);
40566 if(this.labelxs > 0){
40567 label.cls += ' col-xs-' + this.labelxs;
40568 container.cls += ' col-xs-' + (12 - this.labelxs);
40578 var settings = this;
40580 ['xs','sm','md','lg'].map(function(size){
40581 if (settings[size]) {
40582 cfg.cls += ' col-' + size + '-' + settings[size];
40586 this.store = new Roo.data.Store({
40587 proxy : new Roo.data.MemoryProxy({}),
40588 reader : new Roo.data.JsonReader({
40599 'name' : 'dialCode',
40603 'name' : 'priority',
40607 'name' : 'areaCodes',
40614 if(!this.preferedCountries) {
40615 this.preferedCountries = [
40622 var p = this.preferedCountries.reverse();
40625 for (var i = 0; i < p.length; i++) {
40626 for (var j = 0; j < this.allCountries.length; j++) {
40627 if(this.allCountries[j].iso2 == p[i]) {
40628 var t = this.allCountries[j];
40629 this.allCountries.splice(j,1);
40630 this.allCountries.unshift(t);
40636 this.store.proxy.data = {
40638 data: this.allCountries
40644 initEvents : function()
40647 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40649 this.indicator = this.indicatorEl();
40650 this.flag = this.flagEl();
40651 this.dialCodeHolder = this.dialCodeHolderEl();
40653 this.trigger = this.el.select('div.flag-box',true).first();
40654 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40659 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40660 _this.list.setWidth(lw);
40663 this.list.on('mouseover', this.onViewOver, this);
40664 this.list.on('mousemove', this.onViewMove, this);
40665 this.inputEl().on("keyup", this.onKeyUp, this);
40666 this.inputEl().on("keypress", this.onKeyPress, this);
40668 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40670 this.view = new Roo.View(this.list, this.tpl, {
40671 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40674 this.view.on('click', this.onViewClick, this);
40675 this.setValue(this.defaultDialCode);
40678 onTriggerClick : function(e)
40680 Roo.log('trigger click');
40685 if(this.isExpanded()){
40687 this.hasFocus = false;
40689 this.store.load({});
40690 this.hasFocus = true;
40695 isExpanded : function()
40697 return this.list.isVisible();
40700 collapse : function()
40702 if(!this.isExpanded()){
40706 Roo.get(document).un('mousedown', this.collapseIf, this);
40707 Roo.get(document).un('mousewheel', this.collapseIf, this);
40708 this.fireEvent('collapse', this);
40712 expand : function()
40716 if(this.isExpanded() || !this.hasFocus){
40720 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40721 this.list.setWidth(lw);
40724 this.restrictHeight();
40726 Roo.get(document).on('mousedown', this.collapseIf, this);
40727 Roo.get(document).on('mousewheel', this.collapseIf, this);
40729 this.fireEvent('expand', this);
40732 restrictHeight : function()
40734 this.list.alignTo(this.inputEl(), this.listAlign);
40735 this.list.alignTo(this.inputEl(), this.listAlign);
40738 onViewOver : function(e, t)
40740 if(this.inKeyMode){
40743 var item = this.view.findItemFromChild(t);
40746 var index = this.view.indexOf(item);
40747 this.select(index, false);
40752 onViewClick : function(view, doFocus, el, e)
40754 var index = this.view.getSelectedIndexes()[0];
40756 var r = this.store.getAt(index);
40759 this.onSelect(r, index);
40761 if(doFocus !== false && !this.blockFocus){
40762 this.inputEl().focus();
40766 onViewMove : function(e, t)
40768 this.inKeyMode = false;
40771 select : function(index, scrollIntoView)
40773 this.selectedIndex = index;
40774 this.view.select(index);
40775 if(scrollIntoView !== false){
40776 var el = this.view.getNode(index);
40778 this.list.scrollChildIntoView(el, false);
40783 createList : function()
40785 this.list = Roo.get(document.body).createChild({
40787 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40788 style: 'display:none'
40791 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40794 collapseIf : function(e)
40796 var in_combo = e.within(this.el);
40797 var in_list = e.within(this.list);
40798 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40800 if (in_combo || in_list || is_list) {
40806 onSelect : function(record, index)
40808 if(this.fireEvent('beforeselect', this, record, index) !== false){
40810 this.setFlagClass(record.data.iso2);
40811 this.setDialCode(record.data.dialCode);
40812 this.hasFocus = false;
40814 this.fireEvent('select', this, record, index);
40818 flagEl : function()
40820 var flag = this.el.select('div.flag',true).first();
40827 dialCodeHolderEl : function()
40829 var d = this.el.select('input.dial-code-holder',true).first();
40836 setDialCode : function(v)
40838 this.dialCodeHolder.dom.value = '+'+v;
40841 setFlagClass : function(n)
40843 this.flag.dom.className = 'flag '+n;
40846 getValue : function()
40848 var v = this.inputEl().getValue();
40849 if(this.dialCodeHolder) {
40850 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40855 setValue : function(v)
40857 var d = this.getDialCode(v);
40859 //invalid dial code
40860 if(v.length == 0 || !d || d.length == 0) {
40862 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40863 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40869 this.setFlagClass(this.dialCodeMapping[d].iso2);
40870 this.setDialCode(d);
40871 this.inputEl().dom.value = v.replace('+'+d,'');
40872 this.hiddenEl().dom.value = this.getValue();
40877 getDialCode : function(v)
40881 if (v.length == 0) {
40882 return this.dialCodeHolder.dom.value;
40886 if (v.charAt(0) != "+") {
40889 var numericChars = "";
40890 for (var i = 1; i < v.length; i++) {
40891 var c = v.charAt(i);
40894 if (this.dialCodeMapping[numericChars]) {
40895 dialCode = v.substr(1, i);
40897 if (numericChars.length == 4) {
40907 this.setValue(this.defaultDialCode);
40911 hiddenEl : function()
40913 return this.el.select('input.hidden-tel-input',true).first();
40916 // after setting val
40917 onKeyUp : function(e){
40918 this.setValue(this.getValue());
40921 onKeyPress : function(e){
40922 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40929 * @class Roo.bootstrap.MoneyField
40930 * @extends Roo.bootstrap.ComboBox
40931 * Bootstrap MoneyField class
40934 * Create a new MoneyField.
40935 * @param {Object} config Configuration options
40938 Roo.bootstrap.MoneyField = function(config) {
40940 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40944 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40947 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40949 allowDecimals : true,
40951 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40953 decimalSeparator : ".",
40955 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40957 decimalPrecision : 0,
40959 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40961 allowNegative : true,
40963 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40967 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40969 minValue : Number.NEGATIVE_INFINITY,
40971 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40973 maxValue : Number.MAX_VALUE,
40975 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40977 minText : "The minimum value for this field is {0}",
40979 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40981 maxText : "The maximum value for this field is {0}",
40983 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40984 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40986 nanText : "{0} is not a valid number",
40988 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40992 * @cfg {String} defaults currency of the MoneyField
40993 * value should be in lkey
40995 defaultCurrency : false,
40997 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40999 thousandsDelimiter : false,
41001 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
41012 getAutoCreate : function()
41014 var align = this.labelAlign || this.parentLabelAlign();
41026 cls : 'form-control roo-money-amount-input',
41027 autocomplete: 'new-password'
41030 var hiddenInput = {
41034 cls: 'hidden-number-input'
41037 if(this.max_length) {
41038 input.maxlength = this.max_length;
41042 hiddenInput.name = this.name;
41045 if (this.disabled) {
41046 input.disabled = true;
41049 var clg = 12 - this.inputlg;
41050 var cmd = 12 - this.inputmd;
41051 var csm = 12 - this.inputsm;
41052 var cxs = 12 - this.inputxs;
41056 cls : 'row roo-money-field',
41060 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
41064 cls: 'roo-select2-container input-group',
41068 cls : 'form-control roo-money-currency-input',
41069 autocomplete: 'new-password',
41071 name : this.currencyName
41075 cls : 'input-group-addon',
41089 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41093 cls: this.hasFeedback ? 'has-feedback' : '',
41104 if (this.fieldLabel.length) {
41107 tooltip: 'This field is required'
41113 cls: 'control-label',
41119 html: this.fieldLabel
41122 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41128 if(this.indicatorpos == 'right') {
41129 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41136 if(align == 'left') {
41144 if(this.labelWidth > 12){
41145 label.style = "width: " + this.labelWidth + 'px';
41147 if(this.labelWidth < 13 && this.labelmd == 0){
41148 this.labelmd = this.labelWidth;
41150 if(this.labellg > 0){
41151 label.cls += ' col-lg-' + this.labellg;
41152 input.cls += ' col-lg-' + (12 - this.labellg);
41154 if(this.labelmd > 0){
41155 label.cls += ' col-md-' + this.labelmd;
41156 container.cls += ' col-md-' + (12 - this.labelmd);
41158 if(this.labelsm > 0){
41159 label.cls += ' col-sm-' + this.labelsm;
41160 container.cls += ' col-sm-' + (12 - this.labelsm);
41162 if(this.labelxs > 0){
41163 label.cls += ' col-xs-' + this.labelxs;
41164 container.cls += ' col-xs-' + (12 - this.labelxs);
41175 var settings = this;
41177 ['xs','sm','md','lg'].map(function(size){
41178 if (settings[size]) {
41179 cfg.cls += ' col-' + size + '-' + settings[size];
41186 initEvents : function()
41188 this.indicator = this.indicatorEl();
41190 this.initCurrencyEvent();
41192 this.initNumberEvent();
41195 initCurrencyEvent : function()
41198 throw "can not find store for combo";
41201 this.store = Roo.factory(this.store, Roo.data);
41202 this.store.parent = this;
41206 this.triggerEl = this.el.select('.input-group-addon', true).first();
41208 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41213 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41214 _this.list.setWidth(lw);
41217 this.list.on('mouseover', this.onViewOver, this);
41218 this.list.on('mousemove', this.onViewMove, this);
41219 this.list.on('scroll', this.onViewScroll, this);
41222 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41225 this.view = new Roo.View(this.list, this.tpl, {
41226 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41229 this.view.on('click', this.onViewClick, this);
41231 this.store.on('beforeload', this.onBeforeLoad, this);
41232 this.store.on('load', this.onLoad, this);
41233 this.store.on('loadexception', this.onLoadException, this);
41235 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41236 "up" : function(e){
41237 this.inKeyMode = true;
41241 "down" : function(e){
41242 if(!this.isExpanded()){
41243 this.onTriggerClick();
41245 this.inKeyMode = true;
41250 "enter" : function(e){
41253 if(this.fireEvent("specialkey", this, e)){
41254 this.onViewClick(false);
41260 "esc" : function(e){
41264 "tab" : function(e){
41267 if(this.fireEvent("specialkey", this, e)){
41268 this.onViewClick(false);
41276 doRelay : function(foo, bar, hname){
41277 if(hname == 'down' || this.scope.isExpanded()){
41278 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41286 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41290 initNumberEvent : function(e)
41292 this.inputEl().on("keydown" , this.fireKey, this);
41293 this.inputEl().on("focus", this.onFocus, this);
41294 this.inputEl().on("blur", this.onBlur, this);
41296 this.inputEl().relayEvent('keyup', this);
41298 if(this.indicator){
41299 this.indicator.addClass('invisible');
41302 this.originalValue = this.getValue();
41304 if(this.validationEvent == 'keyup'){
41305 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41306 this.inputEl().on('keyup', this.filterValidation, this);
41308 else if(this.validationEvent !== false){
41309 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41312 if(this.selectOnFocus){
41313 this.on("focus", this.preFocus, this);
41316 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41317 this.inputEl().on("keypress", this.filterKeys, this);
41319 this.inputEl().relayEvent('keypress', this);
41322 var allowed = "0123456789";
41324 if(this.allowDecimals){
41325 allowed += this.decimalSeparator;
41328 if(this.allowNegative){
41332 if(this.thousandsDelimiter) {
41336 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41338 var keyPress = function(e){
41340 var k = e.getKey();
41342 var c = e.getCharCode();
41345 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41346 allowed.indexOf(String.fromCharCode(c)) === -1
41352 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41356 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41361 this.inputEl().on("keypress", keyPress, this);
41365 onTriggerClick : function(e)
41372 this.loadNext = false;
41374 if(this.isExpanded()){
41379 this.hasFocus = true;
41381 if(this.triggerAction == 'all') {
41382 this.doQuery(this.allQuery, true);
41386 this.doQuery(this.getRawValue());
41389 getCurrency : function()
41391 var v = this.currencyEl().getValue();
41396 restrictHeight : function()
41398 this.list.alignTo(this.currencyEl(), this.listAlign);
41399 this.list.alignTo(this.currencyEl(), this.listAlign);
41402 onViewClick : function(view, doFocus, el, e)
41404 var index = this.view.getSelectedIndexes()[0];
41406 var r = this.store.getAt(index);
41409 this.onSelect(r, index);
41413 onSelect : function(record, index){
41415 if(this.fireEvent('beforeselect', this, record, index) !== false){
41417 this.setFromCurrencyData(index > -1 ? record.data : false);
41421 this.fireEvent('select', this, record, index);
41425 setFromCurrencyData : function(o)
41429 this.lastCurrency = o;
41431 if (this.currencyField) {
41432 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41434 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41437 this.lastSelectionText = currency;
41439 //setting default currency
41440 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41441 this.setCurrency(this.defaultCurrency);
41445 this.setCurrency(currency);
41448 setFromData : function(o)
41452 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41454 this.setFromCurrencyData(c);
41459 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41461 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41464 this.setValue(value);
41468 setCurrency : function(v)
41470 this.currencyValue = v;
41473 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41478 setValue : function(v)
41480 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41486 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41488 this.inputEl().dom.value = (v == '') ? '' :
41489 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41491 if(!this.allowZero && v === '0') {
41492 this.hiddenEl().dom.value = '';
41493 this.inputEl().dom.value = '';
41500 getRawValue : function()
41502 var v = this.inputEl().getValue();
41507 getValue : function()
41509 return this.fixPrecision(this.parseValue(this.getRawValue()));
41512 parseValue : function(value)
41514 if(this.thousandsDelimiter) {
41516 r = new RegExp(",", "g");
41517 value = value.replace(r, "");
41520 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41521 return isNaN(value) ? '' : value;
41525 fixPrecision : function(value)
41527 if(this.thousandsDelimiter) {
41529 r = new RegExp(",", "g");
41530 value = value.replace(r, "");
41533 var nan = isNaN(value);
41535 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41536 return nan ? '' : value;
41538 return parseFloat(value).toFixed(this.decimalPrecision);
41541 decimalPrecisionFcn : function(v)
41543 return Math.floor(v);
41546 validateValue : function(value)
41548 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41552 var num = this.parseValue(value);
41555 this.markInvalid(String.format(this.nanText, value));
41559 if(num < this.minValue){
41560 this.markInvalid(String.format(this.minText, this.minValue));
41564 if(num > this.maxValue){
41565 this.markInvalid(String.format(this.maxText, this.maxValue));
41572 validate : function()
41574 if(this.disabled || this.allowBlank){
41579 var currency = this.getCurrency();
41581 if(this.validateValue(this.getRawValue()) && currency.length){
41586 this.markInvalid();
41590 getName: function()
41595 beforeBlur : function()
41601 var v = this.parseValue(this.getRawValue());
41608 onBlur : function()
41612 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41613 //this.el.removeClass(this.focusClass);
41616 this.hasFocus = false;
41618 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41622 var v = this.getValue();
41624 if(String(v) !== String(this.startValue)){
41625 this.fireEvent('change', this, v, this.startValue);
41628 this.fireEvent("blur", this);
41631 inputEl : function()
41633 return this.el.select('.roo-money-amount-input', true).first();
41636 currencyEl : function()
41638 return this.el.select('.roo-money-currency-input', true).first();
41641 hiddenEl : function()
41643 return this.el.select('input.hidden-number-input',true).first();
41647 * @class Roo.bootstrap.BezierSignature
41648 * @extends Roo.bootstrap.Component
41649 * Bootstrap BezierSignature class
41650 * This script refer to:
41651 * Title: Signature Pad
41653 * Availability: https://github.com/szimek/signature_pad
41656 * Create a new BezierSignature
41657 * @param {Object} config The config object
41660 Roo.bootstrap.BezierSignature = function(config){
41661 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41667 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41674 mouse_btn_down: true,
41677 * @cfg {int} canvas height
41679 canvas_height: '200px',
41682 * @cfg {float|function} Radius of a single dot.
41687 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41692 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41697 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41702 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41707 * @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.
41709 bg_color: 'rgba(0, 0, 0, 0)',
41712 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41714 dot_color: 'black',
41717 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41719 velocity_filter_weight: 0.7,
41722 * @cfg {function} Callback when stroke begin.
41727 * @cfg {function} Callback when stroke end.
41731 getAutoCreate : function()
41733 var cls = 'roo-signature column';
41736 cls += ' ' + this.cls;
41746 for(var i = 0; i < col_sizes.length; i++) {
41747 if(this[col_sizes[i]]) {
41748 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41758 cls: 'roo-signature-body',
41762 cls: 'roo-signature-body-canvas',
41763 height: this.canvas_height,
41764 width: this.canvas_width
41771 style: 'display: none'
41779 initEvents: function()
41781 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41783 var canvas = this.canvasEl();
41785 // mouse && touch event swapping...
41786 canvas.dom.style.touchAction = 'none';
41787 canvas.dom.style.msTouchAction = 'none';
41789 this.mouse_btn_down = false;
41790 canvas.on('mousedown', this._handleMouseDown, this);
41791 canvas.on('mousemove', this._handleMouseMove, this);
41792 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41794 if (window.PointerEvent) {
41795 canvas.on('pointerdown', this._handleMouseDown, this);
41796 canvas.on('pointermove', this._handleMouseMove, this);
41797 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41800 if ('ontouchstart' in window) {
41801 canvas.on('touchstart', this._handleTouchStart, this);
41802 canvas.on('touchmove', this._handleTouchMove, this);
41803 canvas.on('touchend', this._handleTouchEnd, this);
41806 Roo.EventManager.onWindowResize(this.resize, this, true);
41808 // file input event
41809 this.fileEl().on('change', this.uploadImage, this);
41816 resize: function(){
41818 var canvas = this.canvasEl().dom;
41819 var ctx = this.canvasElCtx();
41820 var img_data = false;
41822 if(canvas.width > 0) {
41823 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41825 // setting canvas width will clean img data
41828 var style = window.getComputedStyle ?
41829 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41831 var padding_left = parseInt(style.paddingLeft) || 0;
41832 var padding_right = parseInt(style.paddingRight) || 0;
41834 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41837 ctx.putImageData(img_data, 0, 0);
41841 _handleMouseDown: function(e)
41843 if (e.browserEvent.which === 1) {
41844 this.mouse_btn_down = true;
41845 this.strokeBegin(e);
41849 _handleMouseMove: function (e)
41851 if (this.mouse_btn_down) {
41852 this.strokeMoveUpdate(e);
41856 _handleMouseUp: function (e)
41858 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41859 this.mouse_btn_down = false;
41864 _handleTouchStart: function (e) {
41866 e.preventDefault();
41867 if (e.browserEvent.targetTouches.length === 1) {
41868 // var touch = e.browserEvent.changedTouches[0];
41869 // this.strokeBegin(touch);
41871 this.strokeBegin(e); // assume e catching the correct xy...
41875 _handleTouchMove: function (e) {
41876 e.preventDefault();
41877 // var touch = event.targetTouches[0];
41878 // _this._strokeMoveUpdate(touch);
41879 this.strokeMoveUpdate(e);
41882 _handleTouchEnd: function (e) {
41883 var wasCanvasTouched = e.target === this.canvasEl().dom;
41884 if (wasCanvasTouched) {
41885 e.preventDefault();
41886 // var touch = event.changedTouches[0];
41887 // _this._strokeEnd(touch);
41892 reset: function () {
41893 this._lastPoints = [];
41894 this._lastVelocity = 0;
41895 this._lastWidth = (this.min_width + this.max_width) / 2;
41896 this.canvasElCtx().fillStyle = this.dot_color;
41899 strokeMoveUpdate: function(e)
41901 this.strokeUpdate(e);
41903 if (this.throttle) {
41904 this.throttleStroke(this.strokeUpdate, this.throttle);
41907 this.strokeUpdate(e);
41911 strokeBegin: function(e)
41913 var newPointGroup = {
41914 color: this.dot_color,
41918 if (typeof this.onBegin === 'function') {
41922 this.curve_data.push(newPointGroup);
41924 this.strokeUpdate(e);
41927 strokeUpdate: function(e)
41929 var rect = this.canvasEl().dom.getBoundingClientRect();
41930 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41931 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41932 var lastPoints = lastPointGroup.points;
41933 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41934 var isLastPointTooClose = lastPoint
41935 ? point.distanceTo(lastPoint) <= this.min_distance
41937 var color = lastPointGroup.color;
41938 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41939 var curve = this.addPoint(point);
41941 this.drawDot({color: color, point: point});
41944 this.drawCurve({color: color, curve: curve});
41954 strokeEnd: function(e)
41956 this.strokeUpdate(e);
41957 if (typeof this.onEnd === 'function') {
41962 addPoint: function (point) {
41963 var _lastPoints = this._lastPoints;
41964 _lastPoints.push(point);
41965 if (_lastPoints.length > 2) {
41966 if (_lastPoints.length === 3) {
41967 _lastPoints.unshift(_lastPoints[0]);
41969 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41970 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41971 _lastPoints.shift();
41977 calculateCurveWidths: function (startPoint, endPoint) {
41978 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41979 (1 - this.velocity_filter_weight) * this._lastVelocity;
41981 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41984 start: this._lastWidth
41987 this._lastVelocity = velocity;
41988 this._lastWidth = newWidth;
41992 drawDot: function (_a) {
41993 var color = _a.color, point = _a.point;
41994 var ctx = this.canvasElCtx();
41995 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41997 this.drawCurveSegment(point.x, point.y, width);
41999 ctx.fillStyle = color;
42003 drawCurve: function (_a) {
42004 var color = _a.color, curve = _a.curve;
42005 var ctx = this.canvasElCtx();
42006 var widthDelta = curve.endWidth - curve.startWidth;
42007 var drawSteps = Math.floor(curve.length()) * 2;
42009 ctx.fillStyle = color;
42010 for (var i = 0; i < drawSteps; i += 1) {
42011 var t = i / drawSteps;
42017 var x = uuu * curve.startPoint.x;
42018 x += 3 * uu * t * curve.control1.x;
42019 x += 3 * u * tt * curve.control2.x;
42020 x += ttt * curve.endPoint.x;
42021 var y = uuu * curve.startPoint.y;
42022 y += 3 * uu * t * curve.control1.y;
42023 y += 3 * u * tt * curve.control2.y;
42024 y += ttt * curve.endPoint.y;
42025 var width = curve.startWidth + ttt * widthDelta;
42026 this.drawCurveSegment(x, y, width);
42032 drawCurveSegment: function (x, y, width) {
42033 var ctx = this.canvasElCtx();
42035 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
42036 this.is_empty = false;
42041 var ctx = this.canvasElCtx();
42042 var canvas = this.canvasEl().dom;
42043 ctx.fillStyle = this.bg_color;
42044 ctx.clearRect(0, 0, canvas.width, canvas.height);
42045 ctx.fillRect(0, 0, canvas.width, canvas.height);
42046 this.curve_data = [];
42048 this.is_empty = true;
42053 return this.el.select('input',true).first();
42056 canvasEl: function()
42058 return this.el.select('canvas',true).first();
42061 canvasElCtx: function()
42063 return this.el.select('canvas',true).first().dom.getContext('2d');
42066 getImage: function(type)
42068 if(this.is_empty) {
42073 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42076 drawFromImage: function(img_src)
42078 var img = new Image();
42080 img.onload = function(){
42081 this.canvasElCtx().drawImage(img, 0, 0);
42086 this.is_empty = false;
42089 selectImage: function()
42091 this.fileEl().dom.click();
42094 uploadImage: function(e)
42096 var reader = new FileReader();
42098 reader.onload = function(e){
42099 var img = new Image();
42100 img.onload = function(){
42102 this.canvasElCtx().drawImage(img, 0, 0);
42104 img.src = e.target.result;
42107 reader.readAsDataURL(e.target.files[0]);
42110 // Bezier Point Constructor
42111 Point: (function () {
42112 function Point(x, y, time) {
42115 this.time = time || Date.now();
42117 Point.prototype.distanceTo = function (start) {
42118 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42120 Point.prototype.equals = function (other) {
42121 return this.x === other.x && this.y === other.y && this.time === other.time;
42123 Point.prototype.velocityFrom = function (start) {
42124 return this.time !== start.time
42125 ? this.distanceTo(start) / (this.time - start.time)
42132 // Bezier Constructor
42133 Bezier: (function () {
42134 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42135 this.startPoint = startPoint;
42136 this.control2 = control2;
42137 this.control1 = control1;
42138 this.endPoint = endPoint;
42139 this.startWidth = startWidth;
42140 this.endWidth = endWidth;
42142 Bezier.fromPoints = function (points, widths, scope) {
42143 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42144 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42145 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42147 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42148 var dx1 = s1.x - s2.x;
42149 var dy1 = s1.y - s2.y;
42150 var dx2 = s2.x - s3.x;
42151 var dy2 = s2.y - s3.y;
42152 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42153 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42154 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42155 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42156 var dxm = m1.x - m2.x;
42157 var dym = m1.y - m2.y;
42158 var k = l2 / (l1 + l2);
42159 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42160 var tx = s2.x - cm.x;
42161 var ty = s2.y - cm.y;
42163 c1: new scope.Point(m1.x + tx, m1.y + ty),
42164 c2: new scope.Point(m2.x + tx, m2.y + ty)
42167 Bezier.prototype.length = function () {
42172 for (var i = 0; i <= steps; i += 1) {
42174 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42175 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42177 var xdiff = cx - px;
42178 var ydiff = cy - py;
42179 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42186 Bezier.prototype.point = function (t, start, c1, c2, end) {
42187 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42188 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42189 + (3.0 * c2 * (1.0 - t) * t * t)
42190 + (end * t * t * t);
42195 throttleStroke: function(fn, wait) {
42196 if (wait === void 0) { wait = 250; }
42198 var timeout = null;
42202 var later = function () {
42203 previous = Date.now();
42205 result = fn.apply(storedContext, storedArgs);
42207 storedContext = null;
42211 return function wrapper() {
42213 for (var _i = 0; _i < arguments.length; _i++) {
42214 args[_i] = arguments[_i];
42216 var now = Date.now();
42217 var remaining = wait - (now - previous);
42218 storedContext = this;
42220 if (remaining <= 0 || remaining > wait) {
42222 clearTimeout(timeout);
42226 result = fn.apply(storedContext, storedArgs);
42228 storedContext = null;
42232 else if (!timeout) {
42233 timeout = window.setTimeout(later, remaining);