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 * Create a data block containing Roo.data.Records from an XML document.
13080 * @param {Object} o An Array of row objects which represents the dataset.
13081 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13082 * a cache of Roo.data.Records.
13084 readRecords : function(o)
13086 var sid = this.meta ? this.meta.id : null;
13087 var recordType = this.recordType, fields = recordType.prototype.fields;
13090 for(var i = 0; i < root.length; i++){
13093 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13094 for(var j = 0, jlen = fields.length; j < jlen; j++){
13095 var f = fields.items[j];
13096 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13097 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13099 values[f.name] = v;
13101 var record = new recordType(values, id);
13103 records[records.length] = record;
13107 totalRecords : records.length
13116 * @class Roo.bootstrap.ComboBox
13117 * @extends Roo.bootstrap.TriggerField
13118 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13119 * @cfg {Boolean} append (true|false) default false
13120 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13121 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13122 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13123 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13124 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13125 * @cfg {Boolean} animate default true
13126 * @cfg {Boolean} emptyResultText only for touch device
13127 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13128 * @cfg {String} emptyTitle default ''
13130 * Create a new ComboBox.
13131 * @param {Object} config Configuration options
13133 Roo.bootstrap.ComboBox = function(config){
13134 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13138 * Fires when the dropdown list is expanded
13139 * @param {Roo.bootstrap.ComboBox} combo This combo box
13144 * Fires when the dropdown list is collapsed
13145 * @param {Roo.bootstrap.ComboBox} combo This combo box
13149 * @event beforeselect
13150 * Fires before a list item is selected. Return false to cancel the selection.
13151 * @param {Roo.bootstrap.ComboBox} combo This combo box
13152 * @param {Roo.data.Record} record The data record returned from the underlying store
13153 * @param {Number} index The index of the selected item in the dropdown list
13155 'beforeselect' : true,
13158 * Fires when a list item is selected
13159 * @param {Roo.bootstrap.ComboBox} combo This combo box
13160 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13161 * @param {Number} index The index of the selected item in the dropdown list
13165 * @event beforequery
13166 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13167 * The event object passed has these properties:
13168 * @param {Roo.bootstrap.ComboBox} combo This combo box
13169 * @param {String} query The query
13170 * @param {Boolean} forceAll true to force "all" query
13171 * @param {Boolean} cancel true to cancel the query
13172 * @param {Object} e The query event object
13174 'beforequery': true,
13177 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13178 * @param {Roo.bootstrap.ComboBox} combo This combo box
13183 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13184 * @param {Roo.bootstrap.ComboBox} combo This combo box
13185 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13190 * Fires when the remove value from the combobox array
13191 * @param {Roo.bootstrap.ComboBox} combo This combo box
13195 * @event afterremove
13196 * Fires when the remove value from the combobox array
13197 * @param {Roo.bootstrap.ComboBox} combo This combo box
13199 'afterremove' : true,
13201 * @event specialfilter
13202 * Fires when specialfilter
13203 * @param {Roo.bootstrap.ComboBox} combo This combo box
13205 'specialfilter' : true,
13208 * Fires when tick the element
13209 * @param {Roo.bootstrap.ComboBox} combo This combo box
13213 * @event touchviewdisplay
13214 * Fires when touch view require special display (default is using displayField)
13215 * @param {Roo.bootstrap.ComboBox} combo This combo box
13216 * @param {Object} cfg set html .
13218 'touchviewdisplay' : true
13223 this.tickItems = [];
13225 this.selectedIndex = -1;
13226 if(this.mode == 'local'){
13227 if(config.queryDelay === undefined){
13228 this.queryDelay = 10;
13230 if(config.minChars === undefined){
13236 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13239 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13240 * rendering into an Roo.Editor, defaults to false)
13243 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13244 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13247 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13250 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13251 * the dropdown list (defaults to undefined, with no header element)
13255 * @cfg {String/Roo.Template} tpl The template to use to render the output
13259 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13261 listWidth: undefined,
13263 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13264 * mode = 'remote' or 'text' if mode = 'local')
13266 displayField: undefined,
13269 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13270 * mode = 'remote' or 'value' if mode = 'local').
13271 * Note: use of a valueField requires the user make a selection
13272 * in order for a value to be mapped.
13274 valueField: undefined,
13276 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13281 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13282 * field's data value (defaults to the underlying DOM element's name)
13284 hiddenName: undefined,
13286 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13290 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13292 selectedClass: 'active',
13295 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13299 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13300 * anchor positions (defaults to 'tl-bl')
13302 listAlign: 'tl-bl?',
13304 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13308 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13309 * query specified by the allQuery config option (defaults to 'query')
13311 triggerAction: 'query',
13313 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13314 * (defaults to 4, does not apply if editable = false)
13318 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13319 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13323 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13324 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13328 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13329 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13333 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13334 * when editable = true (defaults to false)
13336 selectOnFocus:false,
13338 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13340 queryParam: 'query',
13342 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13343 * when mode = 'remote' (defaults to 'Loading...')
13345 loadingText: 'Loading...',
13347 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13351 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13355 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13356 * traditional select (defaults to true)
13360 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13364 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13368 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13369 * listWidth has a higher value)
13373 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13374 * allow the user to set arbitrary text into the field (defaults to false)
13376 forceSelection:false,
13378 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13379 * if typeAhead = true (defaults to 250)
13381 typeAheadDelay : 250,
13383 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13384 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13386 valueNotFoundText : undefined,
13388 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13390 blockFocus : false,
13393 * @cfg {Boolean} disableClear Disable showing of clear button.
13395 disableClear : false,
13397 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13399 alwaysQuery : false,
13402 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13407 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13409 invalidClass : "has-warning",
13412 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13414 validClass : "has-success",
13417 * @cfg {Boolean} specialFilter (true|false) special filter default false
13419 specialFilter : false,
13422 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13424 mobileTouchView : true,
13427 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13429 useNativeIOS : false,
13432 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13434 mobile_restrict_height : false,
13436 ios_options : false,
13448 btnPosition : 'right',
13449 triggerList : true,
13450 showToggleBtn : true,
13452 emptyResultText: 'Empty',
13453 triggerText : 'Select',
13456 // element that contains real text value.. (when hidden is used..)
13458 getAutoCreate : function()
13463 * Render classic select for iso
13466 if(Roo.isIOS && this.useNativeIOS){
13467 cfg = this.getAutoCreateNativeIOS();
13475 if(Roo.isTouch && this.mobileTouchView){
13476 cfg = this.getAutoCreateTouchView();
13483 if(!this.tickable){
13484 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13489 * ComboBox with tickable selections
13492 var align = this.labelAlign || this.parentLabelAlign();
13495 cls : 'form-group roo-combobox-tickable' //input-group
13498 var btn_text_select = '';
13499 var btn_text_done = '';
13500 var btn_text_cancel = '';
13502 if (this.btn_text_show) {
13503 btn_text_select = 'Select';
13504 btn_text_done = 'Done';
13505 btn_text_cancel = 'Cancel';
13510 cls : 'tickable-buttons',
13515 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13516 //html : this.triggerText
13517 html: btn_text_select
13523 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13525 html: btn_text_done
13531 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13533 html: btn_text_cancel
13539 buttons.cn.unshift({
13541 cls: 'roo-select2-search-field-input'
13547 Roo.each(buttons.cn, function(c){
13549 c.cls += ' btn-' + _this.size;
13552 if (_this.disabled) {
13559 style : 'display: contents',
13564 cls: 'form-hidden-field'
13568 cls: 'roo-select2-choices',
13572 cls: 'roo-select2-search-field',
13583 cls: 'roo-select2-container input-group roo-select2-container-multi',
13589 // cls: 'typeahead typeahead-long dropdown-menu',
13590 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13595 if(this.hasFeedback && !this.allowBlank){
13599 cls: 'glyphicon form-control-feedback'
13602 combobox.cn.push(feedback);
13607 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13608 tooltip : 'This field is required'
13610 if (Roo.bootstrap.version == 4) {
13613 style : 'display:none'
13616 if (align ==='left' && this.fieldLabel.length) {
13618 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13625 cls : 'control-label col-form-label',
13626 html : this.fieldLabel
13638 var labelCfg = cfg.cn[1];
13639 var contentCfg = cfg.cn[2];
13642 if(this.indicatorpos == 'right'){
13648 cls : 'control-label col-form-label',
13652 html : this.fieldLabel
13668 labelCfg = cfg.cn[0];
13669 contentCfg = cfg.cn[1];
13673 if(this.labelWidth > 12){
13674 labelCfg.style = "width: " + this.labelWidth + 'px';
13677 if(this.labelWidth < 13 && this.labelmd == 0){
13678 this.labelmd = this.labelWidth;
13681 if(this.labellg > 0){
13682 labelCfg.cls += ' col-lg-' + this.labellg;
13683 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13686 if(this.labelmd > 0){
13687 labelCfg.cls += ' col-md-' + this.labelmd;
13688 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13691 if(this.labelsm > 0){
13692 labelCfg.cls += ' col-sm-' + this.labelsm;
13693 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13696 if(this.labelxs > 0){
13697 labelCfg.cls += ' col-xs-' + this.labelxs;
13698 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13702 } else if ( this.fieldLabel.length) {
13703 // Roo.log(" label");
13708 //cls : 'input-group-addon',
13709 html : this.fieldLabel
13714 if(this.indicatorpos == 'right'){
13718 //cls : 'input-group-addon',
13719 html : this.fieldLabel
13729 // Roo.log(" no label && no align");
13736 ['xs','sm','md','lg'].map(function(size){
13737 if (settings[size]) {
13738 cfg.cls += ' col-' + size + '-' + settings[size];
13746 _initEventsCalled : false,
13749 initEvents: function()
13751 if (this._initEventsCalled) { // as we call render... prevent looping...
13754 this._initEventsCalled = true;
13757 throw "can not find store for combo";
13760 this.indicator = this.indicatorEl();
13762 this.store = Roo.factory(this.store, Roo.data);
13763 this.store.parent = this;
13765 // if we are building from html. then this element is so complex, that we can not really
13766 // use the rendered HTML.
13767 // so we have to trash and replace the previous code.
13768 if (Roo.XComponent.build_from_html) {
13769 // remove this element....
13770 var e = this.el.dom, k=0;
13771 while (e ) { e = e.previousSibling; ++k;}
13776 this.rendered = false;
13778 this.render(this.parent().getChildContainer(true), k);
13781 if(Roo.isIOS && this.useNativeIOS){
13782 this.initIOSView();
13790 if(Roo.isTouch && this.mobileTouchView){
13791 this.initTouchView();
13796 this.initTickableEvents();
13800 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13802 if(this.hiddenName){
13804 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13806 this.hiddenField.dom.value =
13807 this.hiddenValue !== undefined ? this.hiddenValue :
13808 this.value !== undefined ? this.value : '';
13810 // prevent input submission
13811 this.el.dom.removeAttribute('name');
13812 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13817 // this.el.dom.setAttribute('autocomplete', 'off');
13820 var cls = 'x-combo-list';
13822 //this.list = new Roo.Layer({
13823 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13829 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13830 _this.list.setWidth(lw);
13833 this.list.on('mouseover', this.onViewOver, this);
13834 this.list.on('mousemove', this.onViewMove, this);
13835 this.list.on('scroll', this.onViewScroll, this);
13838 this.list.swallowEvent('mousewheel');
13839 this.assetHeight = 0;
13842 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13843 this.assetHeight += this.header.getHeight();
13846 this.innerList = this.list.createChild({cls:cls+'-inner'});
13847 this.innerList.on('mouseover', this.onViewOver, this);
13848 this.innerList.on('mousemove', this.onViewMove, this);
13849 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13851 if(this.allowBlank && !this.pageSize && !this.disableClear){
13852 this.footer = this.list.createChild({cls:cls+'-ft'});
13853 this.pageTb = new Roo.Toolbar(this.footer);
13857 this.footer = this.list.createChild({cls:cls+'-ft'});
13858 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13859 {pageSize: this.pageSize});
13863 if (this.pageTb && this.allowBlank && !this.disableClear) {
13865 this.pageTb.add(new Roo.Toolbar.Fill(), {
13866 cls: 'x-btn-icon x-btn-clear',
13868 handler: function()
13871 _this.clearValue();
13872 _this.onSelect(false, -1);
13877 this.assetHeight += this.footer.getHeight();
13882 this.tpl = Roo.bootstrap.version == 4 ?
13883 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13884 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13887 this.view = new Roo.View(this.list, this.tpl, {
13888 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13890 //this.view.wrapEl.setDisplayed(false);
13891 this.view.on('click', this.onViewClick, this);
13894 this.store.on('beforeload', this.onBeforeLoad, this);
13895 this.store.on('load', this.onLoad, this);
13896 this.store.on('loadexception', this.onLoadException, this);
13898 if(this.resizable){
13899 this.resizer = new Roo.Resizable(this.list, {
13900 pinned:true, handles:'se'
13902 this.resizer.on('resize', function(r, w, h){
13903 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13904 this.listWidth = w;
13905 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13906 this.restrictHeight();
13908 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13911 if(!this.editable){
13912 this.editable = true;
13913 this.setEditable(false);
13918 if (typeof(this.events.add.listeners) != 'undefined') {
13920 this.addicon = this.wrap.createChild(
13921 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13923 this.addicon.on('click', function(e) {
13924 this.fireEvent('add', this);
13927 if (typeof(this.events.edit.listeners) != 'undefined') {
13929 this.editicon = this.wrap.createChild(
13930 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13931 if (this.addicon) {
13932 this.editicon.setStyle('margin-left', '40px');
13934 this.editicon.on('click', function(e) {
13936 // we fire even if inothing is selected..
13937 this.fireEvent('edit', this, this.lastData );
13943 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13944 "up" : function(e){
13945 this.inKeyMode = true;
13949 "down" : function(e){
13950 if(!this.isExpanded()){
13951 this.onTriggerClick();
13953 this.inKeyMode = true;
13958 "enter" : function(e){
13959 // this.onViewClick();
13963 if(this.fireEvent("specialkey", this, e)){
13964 this.onViewClick(false);
13970 "esc" : function(e){
13974 "tab" : function(e){
13977 if(this.fireEvent("specialkey", this, e)){
13978 this.onViewClick(false);
13986 doRelay : function(foo, bar, hname){
13987 if(hname == 'down' || this.scope.isExpanded()){
13988 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13997 this.queryDelay = Math.max(this.queryDelay || 10,
13998 this.mode == 'local' ? 10 : 250);
14001 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14003 if(this.typeAhead){
14004 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14006 if(this.editable !== false){
14007 this.inputEl().on("keyup", this.onKeyUp, this);
14009 if(this.forceSelection){
14010 this.inputEl().on('blur', this.doForce, this);
14014 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14015 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14019 initTickableEvents: function()
14023 if(this.hiddenName){
14025 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14027 this.hiddenField.dom.value =
14028 this.hiddenValue !== undefined ? this.hiddenValue :
14029 this.value !== undefined ? this.value : '';
14031 // prevent input submission
14032 this.el.dom.removeAttribute('name');
14033 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14038 // this.list = this.el.select('ul.dropdown-menu',true).first();
14040 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14041 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14042 if(this.triggerList){
14043 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14046 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14047 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14049 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14050 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14052 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14053 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14055 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14056 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14057 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14060 this.cancelBtn.hide();
14065 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14066 _this.list.setWidth(lw);
14069 this.list.on('mouseover', this.onViewOver, this);
14070 this.list.on('mousemove', this.onViewMove, this);
14072 this.list.on('scroll', this.onViewScroll, this);
14075 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14076 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14079 this.view = new Roo.View(this.list, this.tpl, {
14084 selectedClass: this.selectedClass
14087 //this.view.wrapEl.setDisplayed(false);
14088 this.view.on('click', this.onViewClick, this);
14092 this.store.on('beforeload', this.onBeforeLoad, this);
14093 this.store.on('load', this.onLoad, this);
14094 this.store.on('loadexception', this.onLoadException, this);
14097 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14098 "up" : function(e){
14099 this.inKeyMode = true;
14103 "down" : function(e){
14104 this.inKeyMode = true;
14108 "enter" : function(e){
14109 if(this.fireEvent("specialkey", this, e)){
14110 this.onViewClick(false);
14116 "esc" : function(e){
14117 this.onTickableFooterButtonClick(e, false, false);
14120 "tab" : function(e){
14121 this.fireEvent("specialkey", this, e);
14123 this.onTickableFooterButtonClick(e, false, false);
14130 doRelay : function(e, fn, key){
14131 if(this.scope.isExpanded()){
14132 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14141 this.queryDelay = Math.max(this.queryDelay || 10,
14142 this.mode == 'local' ? 10 : 250);
14145 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14147 if(this.typeAhead){
14148 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14151 if(this.editable !== false){
14152 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14155 this.indicator = this.indicatorEl();
14157 if(this.indicator){
14158 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14159 this.indicator.hide();
14164 onDestroy : function(){
14166 this.view.setStore(null);
14167 this.view.el.removeAllListeners();
14168 this.view.el.remove();
14169 this.view.purgeListeners();
14172 this.list.dom.innerHTML = '';
14176 this.store.un('beforeload', this.onBeforeLoad, this);
14177 this.store.un('load', this.onLoad, this);
14178 this.store.un('loadexception', this.onLoadException, this);
14180 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14184 fireKey : function(e){
14185 if(e.isNavKeyPress() && !this.list.isVisible()){
14186 this.fireEvent("specialkey", this, e);
14191 onResize: function(w, h){
14192 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14194 // if(typeof w != 'number'){
14195 // // we do not handle it!?!?
14198 // var tw = this.trigger.getWidth();
14199 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14200 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14202 // this.inputEl().setWidth( this.adjustWidth('input', x));
14204 // //this.trigger.setStyle('left', x+'px');
14206 // if(this.list && this.listWidth === undefined){
14207 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14208 // this.list.setWidth(lw);
14209 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14217 * Allow or prevent the user from directly editing the field text. If false is passed,
14218 * the user will only be able to select from the items defined in the dropdown list. This method
14219 * is the runtime equivalent of setting the 'editable' config option at config time.
14220 * @param {Boolean} value True to allow the user to directly edit the field text
14222 setEditable : function(value){
14223 if(value == this.editable){
14226 this.editable = value;
14228 this.inputEl().dom.setAttribute('readOnly', true);
14229 this.inputEl().on('mousedown', this.onTriggerClick, this);
14230 this.inputEl().addClass('x-combo-noedit');
14232 this.inputEl().dom.setAttribute('readOnly', false);
14233 this.inputEl().un('mousedown', this.onTriggerClick, this);
14234 this.inputEl().removeClass('x-combo-noedit');
14240 onBeforeLoad : function(combo,opts){
14241 if(!this.hasFocus){
14245 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14247 this.restrictHeight();
14248 this.selectedIndex = -1;
14252 onLoad : function(){
14254 this.hasQuery = false;
14256 if(!this.hasFocus){
14260 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14261 this.loading.hide();
14264 if(this.store.getCount() > 0){
14267 this.restrictHeight();
14268 if(this.lastQuery == this.allQuery){
14269 if(this.editable && !this.tickable){
14270 this.inputEl().dom.select();
14274 !this.selectByValue(this.value, true) &&
14277 !this.store.lastOptions ||
14278 typeof(this.store.lastOptions.add) == 'undefined' ||
14279 this.store.lastOptions.add != true
14282 this.select(0, true);
14285 if(this.autoFocus){
14288 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14289 this.taTask.delay(this.typeAheadDelay);
14293 this.onEmptyResults();
14299 onLoadException : function()
14301 this.hasQuery = false;
14303 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14304 this.loading.hide();
14307 if(this.tickable && this.editable){
14312 // only causes errors at present
14313 //Roo.log(this.store.reader.jsonData);
14314 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14316 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14322 onTypeAhead : function(){
14323 if(this.store.getCount() > 0){
14324 var r = this.store.getAt(0);
14325 var newValue = r.data[this.displayField];
14326 var len = newValue.length;
14327 var selStart = this.getRawValue().length;
14329 if(selStart != len){
14330 this.setRawValue(newValue);
14331 this.selectText(selStart, newValue.length);
14337 onSelect : function(record, index){
14339 if(this.fireEvent('beforeselect', this, record, index) !== false){
14341 this.setFromData(index > -1 ? record.data : false);
14344 this.fireEvent('select', this, record, index);
14349 * Returns the currently selected field value or empty string if no value is set.
14350 * @return {String} value The selected value
14352 getValue : function()
14354 if(Roo.isIOS && this.useNativeIOS){
14355 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14359 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14362 if(this.valueField){
14363 return typeof this.value != 'undefined' ? this.value : '';
14365 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14369 getRawValue : function()
14371 if(Roo.isIOS && this.useNativeIOS){
14372 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14375 var v = this.inputEl().getValue();
14381 * Clears any text/value currently set in the field
14383 clearValue : function(){
14385 if(this.hiddenField){
14386 this.hiddenField.dom.value = '';
14389 this.setRawValue('');
14390 this.lastSelectionText = '';
14391 this.lastData = false;
14393 var close = this.closeTriggerEl();
14404 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14405 * will be displayed in the field. If the value does not match the data value of an existing item,
14406 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14407 * Otherwise the field will be blank (although the value will still be set).
14408 * @param {String} value The value to match
14410 setValue : function(v)
14412 if(Roo.isIOS && this.useNativeIOS){
14413 this.setIOSValue(v);
14423 if(this.valueField){
14424 var r = this.findRecord(this.valueField, v);
14426 text = r.data[this.displayField];
14427 }else if(this.valueNotFoundText !== undefined){
14428 text = this.valueNotFoundText;
14431 this.lastSelectionText = text;
14432 if(this.hiddenField){
14433 this.hiddenField.dom.value = v;
14435 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14438 var close = this.closeTriggerEl();
14441 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14447 * @property {Object} the last set data for the element
14452 * Sets the value of the field based on a object which is related to the record format for the store.
14453 * @param {Object} value the value to set as. or false on reset?
14455 setFromData : function(o){
14462 var dv = ''; // display value
14463 var vv = ''; // value value..
14465 if (this.displayField) {
14466 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14468 // this is an error condition!!!
14469 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14472 if(this.valueField){
14473 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14476 var close = this.closeTriggerEl();
14479 if(dv.length || vv * 1 > 0){
14481 this.blockFocus=true;
14487 if(this.hiddenField){
14488 this.hiddenField.dom.value = vv;
14490 this.lastSelectionText = dv;
14491 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14495 // no hidden field.. - we store the value in 'value', but still display
14496 // display field!!!!
14497 this.lastSelectionText = dv;
14498 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14505 reset : function(){
14506 // overridden so that last data is reset..
14513 this.setValue(this.originalValue);
14514 //this.clearInvalid();
14515 this.lastData = false;
14517 this.view.clearSelections();
14523 findRecord : function(prop, value){
14525 if(this.store.getCount() > 0){
14526 this.store.each(function(r){
14527 if(r.data[prop] == value){
14537 getName: function()
14539 // returns hidden if it's set..
14540 if (!this.rendered) {return ''};
14541 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14545 onViewMove : function(e, t){
14546 this.inKeyMode = false;
14550 onViewOver : function(e, t){
14551 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14554 var item = this.view.findItemFromChild(t);
14557 var index = this.view.indexOf(item);
14558 this.select(index, false);
14563 onViewClick : function(view, doFocus, el, e)
14565 var index = this.view.getSelectedIndexes()[0];
14567 var r = this.store.getAt(index);
14571 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14578 Roo.each(this.tickItems, function(v,k){
14580 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14582 _this.tickItems.splice(k, 1);
14584 if(typeof(e) == 'undefined' && view == false){
14585 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14597 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14598 this.tickItems.push(r.data);
14601 if(typeof(e) == 'undefined' && view == false){
14602 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14609 this.onSelect(r, index);
14611 if(doFocus !== false && !this.blockFocus){
14612 this.inputEl().focus();
14617 restrictHeight : function(){
14618 //this.innerList.dom.style.height = '';
14619 //var inner = this.innerList.dom;
14620 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14621 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14622 //this.list.beginUpdate();
14623 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14624 this.list.alignTo(this.inputEl(), this.listAlign);
14625 this.list.alignTo(this.inputEl(), this.listAlign);
14626 //this.list.endUpdate();
14630 onEmptyResults : function(){
14632 if(this.tickable && this.editable){
14633 this.hasFocus = false;
14634 this.restrictHeight();
14642 * Returns true if the dropdown list is expanded, else false.
14644 isExpanded : function(){
14645 return this.list.isVisible();
14649 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14650 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14651 * @param {String} value The data value of the item to select
14652 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14653 * selected item if it is not currently in view (defaults to true)
14654 * @return {Boolean} True if the value matched an item in the list, else false
14656 selectByValue : function(v, scrollIntoView){
14657 if(v !== undefined && v !== null){
14658 var r = this.findRecord(this.valueField || this.displayField, v);
14660 this.select(this.store.indexOf(r), scrollIntoView);
14668 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14669 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14670 * @param {Number} index The zero-based index of the list item to select
14671 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14672 * selected item if it is not currently in view (defaults to true)
14674 select : function(index, scrollIntoView){
14675 this.selectedIndex = index;
14676 this.view.select(index);
14677 if(scrollIntoView !== false){
14678 var el = this.view.getNode(index);
14680 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14683 this.list.scrollChildIntoView(el, false);
14689 selectNext : function(){
14690 var ct = this.store.getCount();
14692 if(this.selectedIndex == -1){
14694 }else if(this.selectedIndex < ct-1){
14695 this.select(this.selectedIndex+1);
14701 selectPrev : function(){
14702 var ct = this.store.getCount();
14704 if(this.selectedIndex == -1){
14706 }else if(this.selectedIndex != 0){
14707 this.select(this.selectedIndex-1);
14713 onKeyUp : function(e){
14714 if(this.editable !== false && !e.isSpecialKey()){
14715 this.lastKey = e.getKey();
14716 this.dqTask.delay(this.queryDelay);
14721 validateBlur : function(){
14722 return !this.list || !this.list.isVisible();
14726 initQuery : function(){
14728 var v = this.getRawValue();
14730 if(this.tickable && this.editable){
14731 v = this.tickableInputEl().getValue();
14738 doForce : function(){
14739 if(this.inputEl().dom.value.length > 0){
14740 this.inputEl().dom.value =
14741 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14747 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14748 * query allowing the query action to be canceled if needed.
14749 * @param {String} query The SQL query to execute
14750 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14751 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14752 * saved in the current store (defaults to false)
14754 doQuery : function(q, forceAll){
14756 if(q === undefined || q === null){
14761 forceAll: forceAll,
14765 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14770 forceAll = qe.forceAll;
14771 if(forceAll === true || (q.length >= this.minChars)){
14773 this.hasQuery = true;
14775 if(this.lastQuery != q || this.alwaysQuery){
14776 this.lastQuery = q;
14777 if(this.mode == 'local'){
14778 this.selectedIndex = -1;
14780 this.store.clearFilter();
14783 if(this.specialFilter){
14784 this.fireEvent('specialfilter', this);
14789 this.store.filter(this.displayField, q);
14792 this.store.fireEvent("datachanged", this.store);
14799 this.store.baseParams[this.queryParam] = q;
14801 var options = {params : this.getParams(q)};
14804 options.add = true;
14805 options.params.start = this.page * this.pageSize;
14808 this.store.load(options);
14811 * this code will make the page width larger, at the beginning, the list not align correctly,
14812 * we should expand the list on onLoad
14813 * so command out it
14818 this.selectedIndex = -1;
14823 this.loadNext = false;
14827 getParams : function(q){
14829 //p[this.queryParam] = q;
14833 p.limit = this.pageSize;
14839 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14841 collapse : function(){
14842 if(!this.isExpanded()){
14848 this.hasFocus = false;
14852 this.cancelBtn.hide();
14853 this.trigger.show();
14856 this.tickableInputEl().dom.value = '';
14857 this.tickableInputEl().blur();
14862 Roo.get(document).un('mousedown', this.collapseIf, this);
14863 Roo.get(document).un('mousewheel', this.collapseIf, this);
14864 if (!this.editable) {
14865 Roo.get(document).un('keydown', this.listKeyPress, this);
14867 this.fireEvent('collapse', this);
14873 collapseIf : function(e){
14874 var in_combo = e.within(this.el);
14875 var in_list = e.within(this.list);
14876 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14878 if (in_combo || in_list || is_list) {
14879 //e.stopPropagation();
14884 this.onTickableFooterButtonClick(e, false, false);
14892 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14894 expand : function(){
14896 if(this.isExpanded() || !this.hasFocus){
14900 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14901 this.list.setWidth(lw);
14907 this.restrictHeight();
14911 this.tickItems = Roo.apply([], this.item);
14914 this.cancelBtn.show();
14915 this.trigger.hide();
14918 this.tickableInputEl().focus();
14923 Roo.get(document).on('mousedown', this.collapseIf, this);
14924 Roo.get(document).on('mousewheel', this.collapseIf, this);
14925 if (!this.editable) {
14926 Roo.get(document).on('keydown', this.listKeyPress, this);
14929 this.fireEvent('expand', this);
14933 // Implements the default empty TriggerField.onTriggerClick function
14934 onTriggerClick : function(e)
14936 Roo.log('trigger click');
14938 if(this.disabled || !this.triggerList){
14943 this.loadNext = false;
14945 if(this.isExpanded()){
14947 if (!this.blockFocus) {
14948 this.inputEl().focus();
14952 this.hasFocus = true;
14953 if(this.triggerAction == 'all') {
14954 this.doQuery(this.allQuery, true);
14956 this.doQuery(this.getRawValue());
14958 if (!this.blockFocus) {
14959 this.inputEl().focus();
14964 onTickableTriggerClick : function(e)
14971 this.loadNext = false;
14972 this.hasFocus = true;
14974 if(this.triggerAction == 'all') {
14975 this.doQuery(this.allQuery, true);
14977 this.doQuery(this.getRawValue());
14981 onSearchFieldClick : function(e)
14983 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14984 this.onTickableFooterButtonClick(e, false, false);
14988 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14993 this.loadNext = false;
14994 this.hasFocus = true;
14996 if(this.triggerAction == 'all') {
14997 this.doQuery(this.allQuery, true);
14999 this.doQuery(this.getRawValue());
15003 listKeyPress : function(e)
15005 //Roo.log('listkeypress');
15006 // scroll to first matching element based on key pres..
15007 if (e.isSpecialKey()) {
15010 var k = String.fromCharCode(e.getKey()).toUpperCase();
15013 var csel = this.view.getSelectedNodes();
15014 var cselitem = false;
15016 var ix = this.view.indexOf(csel[0]);
15017 cselitem = this.store.getAt(ix);
15018 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15024 this.store.each(function(v) {
15026 // start at existing selection.
15027 if (cselitem.id == v.id) {
15033 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15034 match = this.store.indexOf(v);
15040 if (match === false) {
15041 return true; // no more action?
15044 this.view.select(match);
15045 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15046 sn.scrollIntoView(sn.dom.parentNode, false);
15049 onViewScroll : function(e, t){
15051 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){
15055 this.hasQuery = true;
15057 this.loading = this.list.select('.loading', true).first();
15059 if(this.loading === null){
15060 this.list.createChild({
15062 cls: 'loading roo-select2-more-results roo-select2-active',
15063 html: 'Loading more results...'
15066 this.loading = this.list.select('.loading', true).first();
15068 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15070 this.loading.hide();
15073 this.loading.show();
15078 this.loadNext = true;
15080 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15085 addItem : function(o)
15087 var dv = ''; // display value
15089 if (this.displayField) {
15090 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15092 // this is an error condition!!!
15093 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15100 var choice = this.choices.createChild({
15102 cls: 'roo-select2-search-choice',
15111 cls: 'roo-select2-search-choice-close fa fa-times',
15116 }, this.searchField);
15118 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15120 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15128 this.inputEl().dom.value = '';
15133 onRemoveItem : function(e, _self, o)
15135 e.preventDefault();
15137 this.lastItem = Roo.apply([], this.item);
15139 var index = this.item.indexOf(o.data) * 1;
15142 Roo.log('not this item?!');
15146 this.item.splice(index, 1);
15151 this.fireEvent('remove', this, e);
15157 syncValue : function()
15159 if(!this.item.length){
15166 Roo.each(this.item, function(i){
15167 if(_this.valueField){
15168 value.push(i[_this.valueField]);
15175 this.value = value.join(',');
15177 if(this.hiddenField){
15178 this.hiddenField.dom.value = this.value;
15181 this.store.fireEvent("datachanged", this.store);
15186 clearItem : function()
15188 if(!this.multiple){
15194 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15202 if(this.tickable && !Roo.isTouch){
15203 this.view.refresh();
15207 inputEl: function ()
15209 if(Roo.isIOS && this.useNativeIOS){
15210 return this.el.select('select.roo-ios-select', true).first();
15213 if(Roo.isTouch && this.mobileTouchView){
15214 return this.el.select('input.form-control',true).first();
15218 return this.searchField;
15221 return this.el.select('input.form-control',true).first();
15224 onTickableFooterButtonClick : function(e, btn, el)
15226 e.preventDefault();
15228 this.lastItem = Roo.apply([], this.item);
15230 if(btn && btn.name == 'cancel'){
15231 this.tickItems = Roo.apply([], this.item);
15240 Roo.each(this.tickItems, function(o){
15248 validate : function()
15250 if(this.getVisibilityEl().hasClass('hidden')){
15254 var v = this.getRawValue();
15257 v = this.getValue();
15260 if(this.disabled || this.allowBlank || v.length){
15265 this.markInvalid();
15269 tickableInputEl : function()
15271 if(!this.tickable || !this.editable){
15272 return this.inputEl();
15275 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15279 getAutoCreateTouchView : function()
15284 cls: 'form-group' //input-group
15290 type : this.inputType,
15291 cls : 'form-control x-combo-noedit',
15292 autocomplete: 'new-password',
15293 placeholder : this.placeholder || '',
15298 input.name = this.name;
15302 input.cls += ' input-' + this.size;
15305 if (this.disabled) {
15306 input.disabled = true;
15317 inputblock.cls += ' input-group';
15319 inputblock.cn.unshift({
15321 cls : 'input-group-addon input-group-prepend input-group-text',
15326 if(this.removable && !this.multiple){
15327 inputblock.cls += ' roo-removable';
15329 inputblock.cn.push({
15332 cls : 'roo-combo-removable-btn close'
15336 if(this.hasFeedback && !this.allowBlank){
15338 inputblock.cls += ' has-feedback';
15340 inputblock.cn.push({
15342 cls: 'glyphicon form-control-feedback'
15349 inputblock.cls += (this.before) ? '' : ' input-group';
15351 inputblock.cn.push({
15353 cls : 'input-group-addon input-group-append input-group-text',
15359 var ibwrap = inputblock;
15364 cls: 'roo-select2-choices',
15368 cls: 'roo-select2-search-field',
15381 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15386 cls: 'form-hidden-field'
15392 if(!this.multiple && this.showToggleBtn){
15398 if (this.caret != false) {
15401 cls: 'fa fa-' + this.caret
15408 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15410 Roo.bootstrap.version == 3 ? caret : '',
15413 cls: 'combobox-clear',
15427 combobox.cls += ' roo-select2-container-multi';
15430 var align = this.labelAlign || this.parentLabelAlign();
15432 if (align ==='left' && this.fieldLabel.length) {
15437 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15438 tooltip : 'This field is required'
15442 cls : 'control-label col-form-label',
15443 html : this.fieldLabel
15454 var labelCfg = cfg.cn[1];
15455 var contentCfg = cfg.cn[2];
15458 if(this.indicatorpos == 'right'){
15463 cls : 'control-label col-form-label',
15467 html : this.fieldLabel
15471 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15472 tooltip : 'This field is required'
15485 labelCfg = cfg.cn[0];
15486 contentCfg = cfg.cn[1];
15491 if(this.labelWidth > 12){
15492 labelCfg.style = "width: " + this.labelWidth + 'px';
15495 if(this.labelWidth < 13 && this.labelmd == 0){
15496 this.labelmd = this.labelWidth;
15499 if(this.labellg > 0){
15500 labelCfg.cls += ' col-lg-' + this.labellg;
15501 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15504 if(this.labelmd > 0){
15505 labelCfg.cls += ' col-md-' + this.labelmd;
15506 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15509 if(this.labelsm > 0){
15510 labelCfg.cls += ' col-sm-' + this.labelsm;
15511 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15514 if(this.labelxs > 0){
15515 labelCfg.cls += ' col-xs-' + this.labelxs;
15516 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15520 } else if ( this.fieldLabel.length) {
15524 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15525 tooltip : 'This field is required'
15529 cls : 'control-label',
15530 html : this.fieldLabel
15541 if(this.indicatorpos == 'right'){
15545 cls : 'control-label',
15546 html : this.fieldLabel,
15550 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15551 tooltip : 'This field is required'
15568 var settings = this;
15570 ['xs','sm','md','lg'].map(function(size){
15571 if (settings[size]) {
15572 cfg.cls += ' col-' + size + '-' + settings[size];
15579 initTouchView : function()
15581 this.renderTouchView();
15583 this.touchViewEl.on('scroll', function(){
15584 this.el.dom.scrollTop = 0;
15587 this.originalValue = this.getValue();
15589 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15591 this.inputEl().on("click", this.showTouchView, this);
15592 if (this.triggerEl) {
15593 this.triggerEl.on("click", this.showTouchView, this);
15597 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15598 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15600 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15602 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15603 this.store.on('load', this.onTouchViewLoad, this);
15604 this.store.on('loadexception', this.onTouchViewLoadException, this);
15606 if(this.hiddenName){
15608 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15610 this.hiddenField.dom.value =
15611 this.hiddenValue !== undefined ? this.hiddenValue :
15612 this.value !== undefined ? this.value : '';
15614 this.el.dom.removeAttribute('name');
15615 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15619 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15620 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15623 if(this.removable && !this.multiple){
15624 var close = this.closeTriggerEl();
15626 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15627 close.on('click', this.removeBtnClick, this, close);
15631 * fix the bug in Safari iOS8
15633 this.inputEl().on("focus", function(e){
15634 document.activeElement.blur();
15637 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15644 renderTouchView : function()
15646 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15647 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15649 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15650 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15652 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15653 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15654 this.touchViewBodyEl.setStyle('overflow', 'auto');
15656 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15657 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15659 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15660 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15664 showTouchView : function()
15670 this.touchViewHeaderEl.hide();
15672 if(this.modalTitle.length){
15673 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15674 this.touchViewHeaderEl.show();
15677 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15678 this.touchViewEl.show();
15680 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15682 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15683 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15685 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15687 if(this.modalTitle.length){
15688 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15691 this.touchViewBodyEl.setHeight(bodyHeight);
15695 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15697 this.touchViewEl.addClass('in');
15700 if(this._touchViewMask){
15701 Roo.get(document.body).addClass("x-body-masked");
15702 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15703 this._touchViewMask.setStyle('z-index', 10000);
15704 this._touchViewMask.addClass('show');
15707 this.doTouchViewQuery();
15711 hideTouchView : function()
15713 this.touchViewEl.removeClass('in');
15717 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15719 this.touchViewEl.setStyle('display', 'none');
15722 if(this._touchViewMask){
15723 this._touchViewMask.removeClass('show');
15724 Roo.get(document.body).removeClass("x-body-masked");
15728 setTouchViewValue : function()
15735 Roo.each(this.tickItems, function(o){
15740 this.hideTouchView();
15743 doTouchViewQuery : function()
15752 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15756 if(!this.alwaysQuery || this.mode == 'local'){
15757 this.onTouchViewLoad();
15764 onTouchViewBeforeLoad : function(combo,opts)
15770 onTouchViewLoad : function()
15772 if(this.store.getCount() < 1){
15773 this.onTouchViewEmptyResults();
15777 this.clearTouchView();
15779 var rawValue = this.getRawValue();
15781 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15783 this.tickItems = [];
15785 this.store.data.each(function(d, rowIndex){
15786 var row = this.touchViewListGroup.createChild(template);
15788 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15789 row.addClass(d.data.cls);
15792 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15795 html : d.data[this.displayField]
15798 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15799 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15802 row.removeClass('selected');
15803 if(!this.multiple && this.valueField &&
15804 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15807 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15808 row.addClass('selected');
15811 if(this.multiple && this.valueField &&
15812 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15816 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15817 this.tickItems.push(d.data);
15820 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15824 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15826 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15828 if(this.modalTitle.length){
15829 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15832 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15834 if(this.mobile_restrict_height && listHeight < bodyHeight){
15835 this.touchViewBodyEl.setHeight(listHeight);
15840 if(firstChecked && listHeight > bodyHeight){
15841 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15846 onTouchViewLoadException : function()
15848 this.hideTouchView();
15851 onTouchViewEmptyResults : function()
15853 this.clearTouchView();
15855 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15857 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15861 clearTouchView : function()
15863 this.touchViewListGroup.dom.innerHTML = '';
15866 onTouchViewClick : function(e, el, o)
15868 e.preventDefault();
15871 var rowIndex = o.rowIndex;
15873 var r = this.store.getAt(rowIndex);
15875 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15877 if(!this.multiple){
15878 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15879 c.dom.removeAttribute('checked');
15882 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15884 this.setFromData(r.data);
15886 var close = this.closeTriggerEl();
15892 this.hideTouchView();
15894 this.fireEvent('select', this, r, rowIndex);
15899 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15900 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15901 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15905 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15906 this.addItem(r.data);
15907 this.tickItems.push(r.data);
15911 getAutoCreateNativeIOS : function()
15914 cls: 'form-group' //input-group,
15919 cls : 'roo-ios-select'
15923 combobox.name = this.name;
15926 if (this.disabled) {
15927 combobox.disabled = true;
15930 var settings = this;
15932 ['xs','sm','md','lg'].map(function(size){
15933 if (settings[size]) {
15934 cfg.cls += ' col-' + size + '-' + settings[size];
15944 initIOSView : function()
15946 this.store.on('load', this.onIOSViewLoad, this);
15951 onIOSViewLoad : function()
15953 if(this.store.getCount() < 1){
15957 this.clearIOSView();
15959 if(this.allowBlank) {
15961 var default_text = '-- SELECT --';
15963 if(this.placeholder.length){
15964 default_text = this.placeholder;
15967 if(this.emptyTitle.length){
15968 default_text += ' - ' + this.emptyTitle + ' -';
15971 var opt = this.inputEl().createChild({
15974 html : default_text
15978 o[this.valueField] = 0;
15979 o[this.displayField] = default_text;
15981 this.ios_options.push({
15988 this.store.data.each(function(d, rowIndex){
15992 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15993 html = d.data[this.displayField];
15998 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15999 value = d.data[this.valueField];
16008 if(this.value == d.data[this.valueField]){
16009 option['selected'] = true;
16012 var opt = this.inputEl().createChild(option);
16014 this.ios_options.push({
16021 this.inputEl().on('change', function(){
16022 this.fireEvent('select', this);
16027 clearIOSView: function()
16029 this.inputEl().dom.innerHTML = '';
16031 this.ios_options = [];
16034 setIOSValue: function(v)
16038 if(!this.ios_options){
16042 Roo.each(this.ios_options, function(opts){
16044 opts.el.dom.removeAttribute('selected');
16046 if(opts.data[this.valueField] != v){
16050 opts.el.dom.setAttribute('selected', true);
16056 * @cfg {Boolean} grow
16060 * @cfg {Number} growMin
16064 * @cfg {Number} growMax
16073 Roo.apply(Roo.bootstrap.ComboBox, {
16077 cls: 'modal-header',
16099 cls: 'list-group-item',
16103 cls: 'roo-combobox-list-group-item-value'
16107 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16121 listItemCheckbox : {
16123 cls: 'list-group-item',
16127 cls: 'roo-combobox-list-group-item-value'
16131 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16147 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16152 cls: 'modal-footer',
16160 cls: 'col-xs-6 text-left',
16163 cls: 'btn btn-danger roo-touch-view-cancel',
16169 cls: 'col-xs-6 text-right',
16172 cls: 'btn btn-success roo-touch-view-ok',
16183 Roo.apply(Roo.bootstrap.ComboBox, {
16185 touchViewTemplate : {
16187 cls: 'modal fade roo-combobox-touch-view',
16191 cls: 'modal-dialog',
16192 style : 'position:fixed', // we have to fix position....
16196 cls: 'modal-content',
16198 Roo.bootstrap.ComboBox.header,
16199 Roo.bootstrap.ComboBox.body,
16200 Roo.bootstrap.ComboBox.footer
16209 * Ext JS Library 1.1.1
16210 * Copyright(c) 2006-2007, Ext JS, LLC.
16212 * Originally Released Under LGPL - original licence link has changed is not relivant.
16215 * <script type="text/javascript">
16220 * @extends Roo.util.Observable
16221 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16222 * This class also supports single and multi selection modes. <br>
16223 * Create a data model bound view:
16225 var store = new Roo.data.Store(...);
16227 var view = new Roo.View({
16229 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16231 singleSelect: true,
16232 selectedClass: "ydataview-selected",
16236 // listen for node click?
16237 view.on("click", function(vw, index, node, e){
16238 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16242 dataModel.load("foobar.xml");
16244 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16246 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16247 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16249 * Note: old style constructor is still suported (container, template, config)
16252 * Create a new View
16253 * @param {Object} config The config object
16256 Roo.View = function(config, depreciated_tpl, depreciated_config){
16258 this.parent = false;
16260 if (typeof(depreciated_tpl) == 'undefined') {
16261 // new way.. - universal constructor.
16262 Roo.apply(this, config);
16263 this.el = Roo.get(this.el);
16266 this.el = Roo.get(config);
16267 this.tpl = depreciated_tpl;
16268 Roo.apply(this, depreciated_config);
16270 this.wrapEl = this.el.wrap().wrap();
16271 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16274 if(typeof(this.tpl) == "string"){
16275 this.tpl = new Roo.Template(this.tpl);
16277 // support xtype ctors..
16278 this.tpl = new Roo.factory(this.tpl, Roo);
16282 this.tpl.compile();
16287 * @event beforeclick
16288 * Fires before a click is processed. Returns false to cancel the default action.
16289 * @param {Roo.View} this
16290 * @param {Number} index The index of the target node
16291 * @param {HTMLElement} node The target node
16292 * @param {Roo.EventObject} e The raw event object
16294 "beforeclick" : true,
16297 * Fires when a template node is clicked.
16298 * @param {Roo.View} this
16299 * @param {Number} index The index of the target node
16300 * @param {HTMLElement} node The target node
16301 * @param {Roo.EventObject} e The raw event object
16306 * Fires when a template node is double clicked.
16307 * @param {Roo.View} this
16308 * @param {Number} index The index of the target node
16309 * @param {HTMLElement} node The target node
16310 * @param {Roo.EventObject} e The raw event object
16314 * @event contextmenu
16315 * Fires when a template node is right clicked.
16316 * @param {Roo.View} this
16317 * @param {Number} index The index of the target node
16318 * @param {HTMLElement} node The target node
16319 * @param {Roo.EventObject} e The raw event object
16321 "contextmenu" : true,
16323 * @event selectionchange
16324 * Fires when the selected nodes change.
16325 * @param {Roo.View} this
16326 * @param {Array} selections Array of the selected nodes
16328 "selectionchange" : true,
16331 * @event beforeselect
16332 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16333 * @param {Roo.View} this
16334 * @param {HTMLElement} node The node to be selected
16335 * @param {Array} selections Array of currently selected nodes
16337 "beforeselect" : true,
16339 * @event preparedata
16340 * Fires on every row to render, to allow you to change the data.
16341 * @param {Roo.View} this
16342 * @param {Object} data to be rendered (change this)
16344 "preparedata" : true
16352 "click": this.onClick,
16353 "dblclick": this.onDblClick,
16354 "contextmenu": this.onContextMenu,
16358 this.selections = [];
16360 this.cmp = new Roo.CompositeElementLite([]);
16362 this.store = Roo.factory(this.store, Roo.data);
16363 this.setStore(this.store, true);
16366 if ( this.footer && this.footer.xtype) {
16368 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16370 this.footer.dataSource = this.store;
16371 this.footer.container = fctr;
16372 this.footer = Roo.factory(this.footer, Roo);
16373 fctr.insertFirst(this.el);
16375 // this is a bit insane - as the paging toolbar seems to detach the el..
16376 // dom.parentNode.parentNode.parentNode
16377 // they get detached?
16381 Roo.View.superclass.constructor.call(this);
16386 Roo.extend(Roo.View, Roo.util.Observable, {
16389 * @cfg {Roo.data.Store} store Data store to load data from.
16394 * @cfg {String|Roo.Element} el The container element.
16399 * @cfg {String|Roo.Template} tpl The template used by this View
16403 * @cfg {String} dataName the named area of the template to use as the data area
16404 * Works with domtemplates roo-name="name"
16408 * @cfg {String} selectedClass The css class to add to selected nodes
16410 selectedClass : "x-view-selected",
16412 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16417 * @cfg {String} text to display on mask (default Loading)
16421 * @cfg {Boolean} multiSelect Allow multiple selection
16423 multiSelect : false,
16425 * @cfg {Boolean} singleSelect Allow single selection
16427 singleSelect: false,
16430 * @cfg {Boolean} toggleSelect - selecting
16432 toggleSelect : false,
16435 * @cfg {Boolean} tickable - selecting
16440 * Returns the element this view is bound to.
16441 * @return {Roo.Element}
16443 getEl : function(){
16444 return this.wrapEl;
16450 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16452 refresh : function(){
16453 //Roo.log('refresh');
16456 // if we are using something like 'domtemplate', then
16457 // the what gets used is:
16458 // t.applySubtemplate(NAME, data, wrapping data..)
16459 // the outer template then get' applied with
16460 // the store 'extra data'
16461 // and the body get's added to the
16462 // roo-name="data" node?
16463 // <span class='roo-tpl-{name}'></span> ?????
16467 this.clearSelections();
16468 this.el.update("");
16470 var records = this.store.getRange();
16471 if(records.length < 1) {
16473 // is this valid?? = should it render a template??
16475 this.el.update(this.emptyText);
16479 if (this.dataName) {
16480 this.el.update(t.apply(this.store.meta)); //????
16481 el = this.el.child('.roo-tpl-' + this.dataName);
16484 for(var i = 0, len = records.length; i < len; i++){
16485 var data = this.prepareData(records[i].data, i, records[i]);
16486 this.fireEvent("preparedata", this, data, i, records[i]);
16488 var d = Roo.apply({}, data);
16491 Roo.apply(d, {'roo-id' : Roo.id()});
16495 Roo.each(this.parent.item, function(item){
16496 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16499 Roo.apply(d, {'roo-data-checked' : 'checked'});
16503 html[html.length] = Roo.util.Format.trim(
16505 t.applySubtemplate(this.dataName, d, this.store.meta) :
16512 el.update(html.join(""));
16513 this.nodes = el.dom.childNodes;
16514 this.updateIndexes(0);
16519 * Function to override to reformat the data that is sent to
16520 * the template for each node.
16521 * DEPRICATED - use the preparedata event handler.
16522 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16523 * a JSON object for an UpdateManager bound view).
16525 prepareData : function(data, index, record)
16527 this.fireEvent("preparedata", this, data, index, record);
16531 onUpdate : function(ds, record){
16532 // Roo.log('on update');
16533 this.clearSelections();
16534 var index = this.store.indexOf(record);
16535 var n = this.nodes[index];
16536 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16537 n.parentNode.removeChild(n);
16538 this.updateIndexes(index, index);
16544 onAdd : function(ds, records, index)
16546 //Roo.log(['on Add', ds, records, index] );
16547 this.clearSelections();
16548 if(this.nodes.length == 0){
16552 var n = this.nodes[index];
16553 for(var i = 0, len = records.length; i < len; i++){
16554 var d = this.prepareData(records[i].data, i, records[i]);
16556 this.tpl.insertBefore(n, d);
16559 this.tpl.append(this.el, d);
16562 this.updateIndexes(index);
16565 onRemove : function(ds, record, index){
16566 // Roo.log('onRemove');
16567 this.clearSelections();
16568 var el = this.dataName ?
16569 this.el.child('.roo-tpl-' + this.dataName) :
16572 el.dom.removeChild(this.nodes[index]);
16573 this.updateIndexes(index);
16577 * Refresh an individual node.
16578 * @param {Number} index
16580 refreshNode : function(index){
16581 this.onUpdate(this.store, this.store.getAt(index));
16584 updateIndexes : function(startIndex, endIndex){
16585 var ns = this.nodes;
16586 startIndex = startIndex || 0;
16587 endIndex = endIndex || ns.length - 1;
16588 for(var i = startIndex; i <= endIndex; i++){
16589 ns[i].nodeIndex = i;
16594 * Changes the data store this view uses and refresh the view.
16595 * @param {Store} store
16597 setStore : function(store, initial){
16598 if(!initial && this.store){
16599 this.store.un("datachanged", this.refresh);
16600 this.store.un("add", this.onAdd);
16601 this.store.un("remove", this.onRemove);
16602 this.store.un("update", this.onUpdate);
16603 this.store.un("clear", this.refresh);
16604 this.store.un("beforeload", this.onBeforeLoad);
16605 this.store.un("load", this.onLoad);
16606 this.store.un("loadexception", this.onLoad);
16610 store.on("datachanged", this.refresh, this);
16611 store.on("add", this.onAdd, this);
16612 store.on("remove", this.onRemove, this);
16613 store.on("update", this.onUpdate, this);
16614 store.on("clear", this.refresh, this);
16615 store.on("beforeload", this.onBeforeLoad, this);
16616 store.on("load", this.onLoad, this);
16617 store.on("loadexception", this.onLoad, this);
16625 * onbeforeLoad - masks the loading area.
16628 onBeforeLoad : function(store,opts)
16630 //Roo.log('onBeforeLoad');
16632 this.el.update("");
16634 this.el.mask(this.mask ? this.mask : "Loading" );
16636 onLoad : function ()
16643 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16644 * @param {HTMLElement} node
16645 * @return {HTMLElement} The template node
16647 findItemFromChild : function(node){
16648 var el = this.dataName ?
16649 this.el.child('.roo-tpl-' + this.dataName,true) :
16652 if(!node || node.parentNode == el){
16655 var p = node.parentNode;
16656 while(p && p != el){
16657 if(p.parentNode == el){
16666 onClick : function(e){
16667 var item = this.findItemFromChild(e.getTarget());
16669 var index = this.indexOf(item);
16670 if(this.onItemClick(item, index, e) !== false){
16671 this.fireEvent("click", this, index, item, e);
16674 this.clearSelections();
16679 onContextMenu : function(e){
16680 var item = this.findItemFromChild(e.getTarget());
16682 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16687 onDblClick : function(e){
16688 var item = this.findItemFromChild(e.getTarget());
16690 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16694 onItemClick : function(item, index, e)
16696 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16699 if (this.toggleSelect) {
16700 var m = this.isSelected(item) ? 'unselect' : 'select';
16703 _t[m](item, true, false);
16706 if(this.multiSelect || this.singleSelect){
16707 if(this.multiSelect && e.shiftKey && this.lastSelection){
16708 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16710 this.select(item, this.multiSelect && e.ctrlKey);
16711 this.lastSelection = item;
16714 if(!this.tickable){
16715 e.preventDefault();
16723 * Get the number of selected nodes.
16726 getSelectionCount : function(){
16727 return this.selections.length;
16731 * Get the currently selected nodes.
16732 * @return {Array} An array of HTMLElements
16734 getSelectedNodes : function(){
16735 return this.selections;
16739 * Get the indexes of the selected nodes.
16742 getSelectedIndexes : function(){
16743 var indexes = [], s = this.selections;
16744 for(var i = 0, len = s.length; i < len; i++){
16745 indexes.push(s[i].nodeIndex);
16751 * Clear all selections
16752 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16754 clearSelections : function(suppressEvent){
16755 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16756 this.cmp.elements = this.selections;
16757 this.cmp.removeClass(this.selectedClass);
16758 this.selections = [];
16759 if(!suppressEvent){
16760 this.fireEvent("selectionchange", this, this.selections);
16766 * Returns true if the passed node is selected
16767 * @param {HTMLElement/Number} node The node or node index
16768 * @return {Boolean}
16770 isSelected : function(node){
16771 var s = this.selections;
16775 node = this.getNode(node);
16776 return s.indexOf(node) !== -1;
16781 * @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
16782 * @param {Boolean} keepExisting (optional) true to keep existing selections
16783 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16785 select : function(nodeInfo, keepExisting, suppressEvent){
16786 if(nodeInfo instanceof Array){
16788 this.clearSelections(true);
16790 for(var i = 0, len = nodeInfo.length; i < len; i++){
16791 this.select(nodeInfo[i], true, true);
16795 var node = this.getNode(nodeInfo);
16796 if(!node || this.isSelected(node)){
16797 return; // already selected.
16800 this.clearSelections(true);
16803 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16804 Roo.fly(node).addClass(this.selectedClass);
16805 this.selections.push(node);
16806 if(!suppressEvent){
16807 this.fireEvent("selectionchange", this, this.selections);
16815 * @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
16816 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16817 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16819 unselect : function(nodeInfo, keepExisting, suppressEvent)
16821 if(nodeInfo instanceof Array){
16822 Roo.each(this.selections, function(s) {
16823 this.unselect(s, nodeInfo);
16827 var node = this.getNode(nodeInfo);
16828 if(!node || !this.isSelected(node)){
16829 //Roo.log("not selected");
16830 return; // not selected.
16834 Roo.each(this.selections, function(s) {
16836 Roo.fly(node).removeClass(this.selectedClass);
16843 this.selections= ns;
16844 this.fireEvent("selectionchange", this, this.selections);
16848 * Gets a template node.
16849 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16850 * @return {HTMLElement} The node or null if it wasn't found
16852 getNode : function(nodeInfo){
16853 if(typeof nodeInfo == "string"){
16854 return document.getElementById(nodeInfo);
16855 }else if(typeof nodeInfo == "number"){
16856 return this.nodes[nodeInfo];
16862 * Gets a range template nodes.
16863 * @param {Number} startIndex
16864 * @param {Number} endIndex
16865 * @return {Array} An array of nodes
16867 getNodes : function(start, end){
16868 var ns = this.nodes;
16869 start = start || 0;
16870 end = typeof end == "undefined" ? ns.length - 1 : end;
16873 for(var i = start; i <= end; i++){
16877 for(var i = start; i >= end; i--){
16885 * Finds the index of the passed node
16886 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16887 * @return {Number} The index of the node or -1
16889 indexOf : function(node){
16890 node = this.getNode(node);
16891 if(typeof node.nodeIndex == "number"){
16892 return node.nodeIndex;
16894 var ns = this.nodes;
16895 for(var i = 0, len = ns.length; i < len; i++){
16906 * based on jquery fullcalendar
16910 Roo.bootstrap = Roo.bootstrap || {};
16912 * @class Roo.bootstrap.Calendar
16913 * @extends Roo.bootstrap.Component
16914 * Bootstrap Calendar class
16915 * @cfg {Boolean} loadMask (true|false) default false
16916 * @cfg {Object} header generate the user specific header of the calendar, default false
16919 * Create a new Container
16920 * @param {Object} config The config object
16925 Roo.bootstrap.Calendar = function(config){
16926 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16930 * Fires when a date is selected
16931 * @param {DatePicker} this
16932 * @param {Date} date The selected date
16936 * @event monthchange
16937 * Fires when the displayed month changes
16938 * @param {DatePicker} this
16939 * @param {Date} date The selected month
16941 'monthchange': true,
16943 * @event evententer
16944 * Fires when mouse over an event
16945 * @param {Calendar} this
16946 * @param {event} Event
16948 'evententer': true,
16950 * @event eventleave
16951 * Fires when the mouse leaves an
16952 * @param {Calendar} this
16955 'eventleave': true,
16957 * @event eventclick
16958 * Fires when the mouse click an
16959 * @param {Calendar} this
16968 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16971 * @cfg {Number} startDay
16972 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16980 getAutoCreate : function(){
16983 var fc_button = function(name, corner, style, content ) {
16984 return Roo.apply({},{
16986 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16988 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16991 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17002 style : 'width:100%',
17009 cls : 'fc-header-left',
17011 fc_button('prev', 'left', 'arrow', '‹' ),
17012 fc_button('next', 'right', 'arrow', '›' ),
17013 { tag: 'span', cls: 'fc-header-space' },
17014 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17022 cls : 'fc-header-center',
17026 cls: 'fc-header-title',
17029 html : 'month / year'
17037 cls : 'fc-header-right',
17039 /* fc_button('month', 'left', '', 'month' ),
17040 fc_button('week', '', '', 'week' ),
17041 fc_button('day', 'right', '', 'day' )
17053 header = this.header;
17056 var cal_heads = function() {
17058 // fixme - handle this.
17060 for (var i =0; i < Date.dayNames.length; i++) {
17061 var d = Date.dayNames[i];
17064 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17065 html : d.substring(0,3)
17069 ret[0].cls += ' fc-first';
17070 ret[6].cls += ' fc-last';
17073 var cal_cell = function(n) {
17076 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17081 cls: 'fc-day-number',
17085 cls: 'fc-day-content',
17089 style: 'position: relative;' // height: 17px;
17101 var cal_rows = function() {
17104 for (var r = 0; r < 6; r++) {
17111 for (var i =0; i < Date.dayNames.length; i++) {
17112 var d = Date.dayNames[i];
17113 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17116 row.cn[0].cls+=' fc-first';
17117 row.cn[0].cn[0].style = 'min-height:90px';
17118 row.cn[6].cls+=' fc-last';
17122 ret[0].cls += ' fc-first';
17123 ret[4].cls += ' fc-prev-last';
17124 ret[5].cls += ' fc-last';
17131 cls: 'fc-border-separate',
17132 style : 'width:100%',
17140 cls : 'fc-first fc-last',
17158 cls : 'fc-content',
17159 style : "position: relative;",
17162 cls : 'fc-view fc-view-month fc-grid',
17163 style : 'position: relative',
17164 unselectable : 'on',
17167 cls : 'fc-event-container',
17168 style : 'position:absolute;z-index:8;top:0;left:0;'
17186 initEvents : function()
17189 throw "can not find store for calendar";
17195 style: "text-align:center",
17199 style: "background-color:white;width:50%;margin:250 auto",
17203 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17214 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17216 var size = this.el.select('.fc-content', true).first().getSize();
17217 this.maskEl.setSize(size.width, size.height);
17218 this.maskEl.enableDisplayMode("block");
17219 if(!this.loadMask){
17220 this.maskEl.hide();
17223 this.store = Roo.factory(this.store, Roo.data);
17224 this.store.on('load', this.onLoad, this);
17225 this.store.on('beforeload', this.onBeforeLoad, this);
17229 this.cells = this.el.select('.fc-day',true);
17230 //Roo.log(this.cells);
17231 this.textNodes = this.el.query('.fc-day-number');
17232 this.cells.addClassOnOver('fc-state-hover');
17234 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17235 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17236 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17237 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17239 this.on('monthchange', this.onMonthChange, this);
17241 this.update(new Date().clearTime());
17244 resize : function() {
17245 var sz = this.el.getSize();
17247 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17248 this.el.select('.fc-day-content div',true).setHeight(34);
17253 showPrevMonth : function(e){
17254 this.update(this.activeDate.add("mo", -1));
17256 showToday : function(e){
17257 this.update(new Date().clearTime());
17260 showNextMonth : function(e){
17261 this.update(this.activeDate.add("mo", 1));
17265 showPrevYear : function(){
17266 this.update(this.activeDate.add("y", -1));
17270 showNextYear : function(){
17271 this.update(this.activeDate.add("y", 1));
17276 update : function(date)
17278 var vd = this.activeDate;
17279 this.activeDate = date;
17280 // if(vd && this.el){
17281 // var t = date.getTime();
17282 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17283 // Roo.log('using add remove');
17285 // this.fireEvent('monthchange', this, date);
17287 // this.cells.removeClass("fc-state-highlight");
17288 // this.cells.each(function(c){
17289 // if(c.dateValue == t){
17290 // c.addClass("fc-state-highlight");
17291 // setTimeout(function(){
17292 // try{c.dom.firstChild.focus();}catch(e){}
17302 var days = date.getDaysInMonth();
17304 var firstOfMonth = date.getFirstDateOfMonth();
17305 var startingPos = firstOfMonth.getDay()-this.startDay;
17307 if(startingPos < this.startDay){
17311 var pm = date.add(Date.MONTH, -1);
17312 var prevStart = pm.getDaysInMonth()-startingPos;
17314 this.cells = this.el.select('.fc-day',true);
17315 this.textNodes = this.el.query('.fc-day-number');
17316 this.cells.addClassOnOver('fc-state-hover');
17318 var cells = this.cells.elements;
17319 var textEls = this.textNodes;
17321 Roo.each(cells, function(cell){
17322 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17325 days += startingPos;
17327 // convert everything to numbers so it's fast
17328 var day = 86400000;
17329 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17332 //Roo.log(prevStart);
17334 var today = new Date().clearTime().getTime();
17335 var sel = date.clearTime().getTime();
17336 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17337 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17338 var ddMatch = this.disabledDatesRE;
17339 var ddText = this.disabledDatesText;
17340 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17341 var ddaysText = this.disabledDaysText;
17342 var format = this.format;
17344 var setCellClass = function(cal, cell){
17348 //Roo.log('set Cell Class');
17350 var t = d.getTime();
17354 cell.dateValue = t;
17356 cell.className += " fc-today";
17357 cell.className += " fc-state-highlight";
17358 cell.title = cal.todayText;
17361 // disable highlight in other month..
17362 //cell.className += " fc-state-highlight";
17367 cell.className = " fc-state-disabled";
17368 cell.title = cal.minText;
17372 cell.className = " fc-state-disabled";
17373 cell.title = cal.maxText;
17377 if(ddays.indexOf(d.getDay()) != -1){
17378 cell.title = ddaysText;
17379 cell.className = " fc-state-disabled";
17382 if(ddMatch && format){
17383 var fvalue = d.dateFormat(format);
17384 if(ddMatch.test(fvalue)){
17385 cell.title = ddText.replace("%0", fvalue);
17386 cell.className = " fc-state-disabled";
17390 if (!cell.initialClassName) {
17391 cell.initialClassName = cell.dom.className;
17394 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17399 for(; i < startingPos; i++) {
17400 textEls[i].innerHTML = (++prevStart);
17401 d.setDate(d.getDate()+1);
17403 cells[i].className = "fc-past fc-other-month";
17404 setCellClass(this, cells[i]);
17409 for(; i < days; i++){
17410 intDay = i - startingPos + 1;
17411 textEls[i].innerHTML = (intDay);
17412 d.setDate(d.getDate()+1);
17414 cells[i].className = ''; // "x-date-active";
17415 setCellClass(this, cells[i]);
17419 for(; i < 42; i++) {
17420 textEls[i].innerHTML = (++extraDays);
17421 d.setDate(d.getDate()+1);
17423 cells[i].className = "fc-future fc-other-month";
17424 setCellClass(this, cells[i]);
17427 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17429 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17431 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17432 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17434 if(totalRows != 6){
17435 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17436 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17439 this.fireEvent('monthchange', this, date);
17443 if(!this.internalRender){
17444 var main = this.el.dom.firstChild;
17445 var w = main.offsetWidth;
17446 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17447 Roo.fly(main).setWidth(w);
17448 this.internalRender = true;
17449 // opera does not respect the auto grow header center column
17450 // then, after it gets a width opera refuses to recalculate
17451 // without a second pass
17452 if(Roo.isOpera && !this.secondPass){
17453 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17454 this.secondPass = true;
17455 this.update.defer(10, this, [date]);
17462 findCell : function(dt) {
17463 dt = dt.clearTime().getTime();
17465 this.cells.each(function(c){
17466 //Roo.log("check " +c.dateValue + '?=' + dt);
17467 if(c.dateValue == dt){
17477 findCells : function(ev) {
17478 var s = ev.start.clone().clearTime().getTime();
17480 var e= ev.end.clone().clearTime().getTime();
17483 this.cells.each(function(c){
17484 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17486 if(c.dateValue > e){
17489 if(c.dateValue < s){
17498 // findBestRow: function(cells)
17502 // for (var i =0 ; i < cells.length;i++) {
17503 // ret = Math.max(cells[i].rows || 0,ret);
17510 addItem : function(ev)
17512 // look for vertical location slot in
17513 var cells = this.findCells(ev);
17515 // ev.row = this.findBestRow(cells);
17517 // work out the location.
17521 for(var i =0; i < cells.length; i++) {
17523 cells[i].row = cells[0].row;
17526 cells[i].row = cells[i].row + 1;
17536 if (crow.start.getY() == cells[i].getY()) {
17538 crow.end = cells[i];
17555 cells[0].events.push(ev);
17557 this.calevents.push(ev);
17560 clearEvents: function() {
17562 if(!this.calevents){
17566 Roo.each(this.cells.elements, function(c){
17572 Roo.each(this.calevents, function(e) {
17573 Roo.each(e.els, function(el) {
17574 el.un('mouseenter' ,this.onEventEnter, this);
17575 el.un('mouseleave' ,this.onEventLeave, this);
17580 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17586 renderEvents: function()
17590 this.cells.each(function(c) {
17599 if(c.row != c.events.length){
17600 r = 4 - (4 - (c.row - c.events.length));
17603 c.events = ev.slice(0, r);
17604 c.more = ev.slice(r);
17606 if(c.more.length && c.more.length == 1){
17607 c.events.push(c.more.pop());
17610 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17614 this.cells.each(function(c) {
17616 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17619 for (var e = 0; e < c.events.length; e++){
17620 var ev = c.events[e];
17621 var rows = ev.rows;
17623 for(var i = 0; i < rows.length; i++) {
17625 // how many rows should it span..
17628 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17629 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17631 unselectable : "on",
17634 cls: 'fc-event-inner',
17638 // cls: 'fc-event-time',
17639 // html : cells.length > 1 ? '' : ev.time
17643 cls: 'fc-event-title',
17644 html : String.format('{0}', ev.title)
17651 cls: 'ui-resizable-handle ui-resizable-e',
17652 html : '  '
17659 cfg.cls += ' fc-event-start';
17661 if ((i+1) == rows.length) {
17662 cfg.cls += ' fc-event-end';
17665 var ctr = _this.el.select('.fc-event-container',true).first();
17666 var cg = ctr.createChild(cfg);
17668 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17669 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17671 var r = (c.more.length) ? 1 : 0;
17672 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17673 cg.setWidth(ebox.right - sbox.x -2);
17675 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17676 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17677 cg.on('click', _this.onEventClick, _this, ev);
17688 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17689 style : 'position: absolute',
17690 unselectable : "on",
17693 cls: 'fc-event-inner',
17697 cls: 'fc-event-title',
17705 cls: 'ui-resizable-handle ui-resizable-e',
17706 html : '  '
17712 var ctr = _this.el.select('.fc-event-container',true).first();
17713 var cg = ctr.createChild(cfg);
17715 var sbox = c.select('.fc-day-content',true).first().getBox();
17716 var ebox = c.select('.fc-day-content',true).first().getBox();
17718 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17719 cg.setWidth(ebox.right - sbox.x -2);
17721 cg.on('click', _this.onMoreEventClick, _this, c.more);
17731 onEventEnter: function (e, el,event,d) {
17732 this.fireEvent('evententer', this, el, event);
17735 onEventLeave: function (e, el,event,d) {
17736 this.fireEvent('eventleave', this, el, event);
17739 onEventClick: function (e, el,event,d) {
17740 this.fireEvent('eventclick', this, el, event);
17743 onMonthChange: function () {
17747 onMoreEventClick: function(e, el, more)
17751 this.calpopover.placement = 'right';
17752 this.calpopover.setTitle('More');
17754 this.calpopover.setContent('');
17756 var ctr = this.calpopover.el.select('.popover-content', true).first();
17758 Roo.each(more, function(m){
17760 cls : 'fc-event-hori fc-event-draggable',
17763 var cg = ctr.createChild(cfg);
17765 cg.on('click', _this.onEventClick, _this, m);
17768 this.calpopover.show(el);
17773 onLoad: function ()
17775 this.calevents = [];
17778 if(this.store.getCount() > 0){
17779 this.store.data.each(function(d){
17782 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17783 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17784 time : d.data.start_time,
17785 title : d.data.title,
17786 description : d.data.description,
17787 venue : d.data.venue
17792 this.renderEvents();
17794 if(this.calevents.length && this.loadMask){
17795 this.maskEl.hide();
17799 onBeforeLoad: function()
17801 this.clearEvents();
17803 this.maskEl.show();
17817 * @class Roo.bootstrap.Popover
17818 * @extends Roo.bootstrap.Component
17819 * Bootstrap Popover class
17820 * @cfg {String} html contents of the popover (or false to use children..)
17821 * @cfg {String} title of popover (or false to hide)
17822 * @cfg {String} placement how it is placed
17823 * @cfg {String} trigger click || hover (or false to trigger manually)
17824 * @cfg {String} over what (parent or false to trigger manually.)
17825 * @cfg {Number} delay - delay before showing
17828 * Create a new Popover
17829 * @param {Object} config The config object
17832 Roo.bootstrap.Popover = function(config){
17833 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17839 * After the popover show
17841 * @param {Roo.bootstrap.Popover} this
17846 * After the popover hide
17848 * @param {Roo.bootstrap.Popover} this
17854 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17856 title: 'Fill in a title',
17859 placement : 'right',
17860 trigger : 'hover', // hover
17866 can_build_overlaid : false,
17868 getChildContainer : function()
17870 return this.el.select('.popover-content',true).first();
17873 getAutoCreate : function(){
17876 cls : 'popover roo-dynamic',
17877 style: 'display:block',
17883 cls : 'popover-inner',
17887 cls: 'popover-title popover-header',
17891 cls : 'popover-content popover-body',
17902 setTitle: function(str)
17905 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17907 setContent: function(str)
17910 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17912 // as it get's added to the bottom of the page.
17913 onRender : function(ct, position)
17915 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17917 var cfg = Roo.apply({}, this.getAutoCreate());
17921 cfg.cls += ' ' + this.cls;
17924 cfg.style = this.style;
17926 //Roo.log("adding to ");
17927 this.el = Roo.get(document.body).createChild(cfg, position);
17928 // Roo.log(this.el);
17933 initEvents : function()
17935 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17936 this.el.enableDisplayMode('block');
17938 if (this.over === false) {
17941 if (this.triggers === false) {
17944 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17945 var triggers = this.trigger ? this.trigger.split(' ') : [];
17946 Roo.each(triggers, function(trigger) {
17948 if (trigger == 'click') {
17949 on_el.on('click', this.toggle, this);
17950 } else if (trigger != 'manual') {
17951 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17952 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17954 on_el.on(eventIn ,this.enter, this);
17955 on_el.on(eventOut, this.leave, this);
17966 toggle : function () {
17967 this.hoverState == 'in' ? this.leave() : this.enter();
17970 enter : function () {
17972 clearTimeout(this.timeout);
17974 this.hoverState = 'in';
17976 if (!this.delay || !this.delay.show) {
17981 this.timeout = setTimeout(function () {
17982 if (_t.hoverState == 'in') {
17985 }, this.delay.show)
17988 leave : function() {
17989 clearTimeout(this.timeout);
17991 this.hoverState = 'out';
17993 if (!this.delay || !this.delay.hide) {
17998 this.timeout = setTimeout(function () {
17999 if (_t.hoverState == 'out') {
18002 }, this.delay.hide)
18005 show : function (on_el)
18008 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18012 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18013 if (this.html !== false) {
18014 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18016 this.el.removeClass([
18017 'fade','top','bottom', 'left', 'right','in',
18018 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18020 if (!this.title.length) {
18021 this.el.select('.popover-title',true).hide();
18024 var placement = typeof this.placement == 'function' ?
18025 this.placement.call(this, this.el, on_el) :
18028 var autoToken = /\s?auto?\s?/i;
18029 var autoPlace = autoToken.test(placement);
18031 placement = placement.replace(autoToken, '') || 'top';
18035 //this.el.setXY([0,0]);
18037 this.el.dom.style.display='block';
18038 this.el.addClass(placement);
18040 //this.el.appendTo(on_el);
18042 var p = this.getPosition();
18043 var box = this.el.getBox();
18048 var align = Roo.bootstrap.Popover.alignment[placement];
18051 this.el.alignTo(on_el, align[0],align[1]);
18052 //var arrow = this.el.select('.arrow',true).first();
18053 //arrow.set(align[2],
18055 this.el.addClass('in');
18058 if (this.el.hasClass('fade')) {
18062 this.hoverState = 'in';
18064 this.fireEvent('show', this);
18069 this.el.setXY([0,0]);
18070 this.el.removeClass('in');
18072 this.hoverState = null;
18074 this.fireEvent('hide', this);
18079 Roo.bootstrap.Popover.alignment = {
18080 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18081 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18082 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18083 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18094 * @class Roo.bootstrap.Progress
18095 * @extends Roo.bootstrap.Component
18096 * Bootstrap Progress class
18097 * @cfg {Boolean} striped striped of the progress bar
18098 * @cfg {Boolean} active animated of the progress bar
18102 * Create a new Progress
18103 * @param {Object} config The config object
18106 Roo.bootstrap.Progress = function(config){
18107 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18110 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18115 getAutoCreate : function(){
18123 cfg.cls += ' progress-striped';
18127 cfg.cls += ' active';
18146 * @class Roo.bootstrap.ProgressBar
18147 * @extends Roo.bootstrap.Component
18148 * Bootstrap ProgressBar class
18149 * @cfg {Number} aria_valuenow aria-value now
18150 * @cfg {Number} aria_valuemin aria-value min
18151 * @cfg {Number} aria_valuemax aria-value max
18152 * @cfg {String} label label for the progress bar
18153 * @cfg {String} panel (success | info | warning | danger )
18154 * @cfg {String} role role of the progress bar
18155 * @cfg {String} sr_only text
18159 * Create a new ProgressBar
18160 * @param {Object} config The config object
18163 Roo.bootstrap.ProgressBar = function(config){
18164 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18167 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18171 aria_valuemax : 100,
18177 getAutoCreate : function()
18182 cls: 'progress-bar',
18183 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18195 cfg.role = this.role;
18198 if(this.aria_valuenow){
18199 cfg['aria-valuenow'] = this.aria_valuenow;
18202 if(this.aria_valuemin){
18203 cfg['aria-valuemin'] = this.aria_valuemin;
18206 if(this.aria_valuemax){
18207 cfg['aria-valuemax'] = this.aria_valuemax;
18210 if(this.label && !this.sr_only){
18211 cfg.html = this.label;
18215 cfg.cls += ' progress-bar-' + this.panel;
18221 update : function(aria_valuenow)
18223 this.aria_valuenow = aria_valuenow;
18225 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18240 * @class Roo.bootstrap.TabGroup
18241 * @extends Roo.bootstrap.Column
18242 * Bootstrap Column class
18243 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18244 * @cfg {Boolean} carousel true to make the group behave like a carousel
18245 * @cfg {Boolean} bullets show bullets for the panels
18246 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18247 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18248 * @cfg {Boolean} showarrow (true|false) show arrow default true
18251 * Create a new TabGroup
18252 * @param {Object} config The config object
18255 Roo.bootstrap.TabGroup = function(config){
18256 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18258 this.navId = Roo.id();
18261 Roo.bootstrap.TabGroup.register(this);
18265 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18268 transition : false,
18273 slideOnTouch : false,
18276 getAutoCreate : function()
18278 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18280 cfg.cls += ' tab-content';
18282 if (this.carousel) {
18283 cfg.cls += ' carousel slide';
18286 cls : 'carousel-inner',
18290 if(this.bullets && !Roo.isTouch){
18293 cls : 'carousel-bullets',
18297 if(this.bullets_cls){
18298 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18305 cfg.cn[0].cn.push(bullets);
18308 if(this.showarrow){
18309 cfg.cn[0].cn.push({
18311 class : 'carousel-arrow',
18315 class : 'carousel-prev',
18319 class : 'fa fa-chevron-left'
18325 class : 'carousel-next',
18329 class : 'fa fa-chevron-right'
18342 initEvents: function()
18344 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18345 // this.el.on("touchstart", this.onTouchStart, this);
18348 if(this.autoslide){
18351 this.slideFn = window.setInterval(function() {
18352 _this.showPanelNext();
18356 if(this.showarrow){
18357 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18358 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18364 // onTouchStart : function(e, el, o)
18366 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18370 // this.showPanelNext();
18374 getChildContainer : function()
18376 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18380 * register a Navigation item
18381 * @param {Roo.bootstrap.NavItem} the navitem to add
18383 register : function(item)
18385 this.tabs.push( item);
18386 item.navId = this.navId; // not really needed..
18391 getActivePanel : function()
18394 Roo.each(this.tabs, function(t) {
18404 getPanelByName : function(n)
18407 Roo.each(this.tabs, function(t) {
18408 if (t.tabId == n) {
18416 indexOfPanel : function(p)
18419 Roo.each(this.tabs, function(t,i) {
18420 if (t.tabId == p.tabId) {
18429 * show a specific panel
18430 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18431 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18433 showPanel : function (pan)
18435 if(this.transition || typeof(pan) == 'undefined'){
18436 Roo.log("waiting for the transitionend");
18440 if (typeof(pan) == 'number') {
18441 pan = this.tabs[pan];
18444 if (typeof(pan) == 'string') {
18445 pan = this.getPanelByName(pan);
18448 var cur = this.getActivePanel();
18451 Roo.log('pan or acitve pan is undefined');
18455 if (pan.tabId == this.getActivePanel().tabId) {
18459 if (false === cur.fireEvent('beforedeactivate')) {
18463 if(this.bullets > 0 && !Roo.isTouch){
18464 this.setActiveBullet(this.indexOfPanel(pan));
18467 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18469 //class="carousel-item carousel-item-next carousel-item-left"
18471 this.transition = true;
18472 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18473 var lr = dir == 'next' ? 'left' : 'right';
18474 pan.el.addClass(dir); // or prev
18475 pan.el.addClass('carousel-item-' + dir); // or prev
18476 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18477 cur.el.addClass(lr); // or right
18478 pan.el.addClass(lr);
18479 cur.el.addClass('carousel-item-' +lr); // or right
18480 pan.el.addClass('carousel-item-' +lr);
18484 cur.el.on('transitionend', function() {
18485 Roo.log("trans end?");
18487 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18488 pan.setActive(true);
18490 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18491 cur.setActive(false);
18493 _this.transition = false;
18495 }, this, { single: true } );
18500 cur.setActive(false);
18501 pan.setActive(true);
18506 showPanelNext : function()
18508 var i = this.indexOfPanel(this.getActivePanel());
18510 if (i >= this.tabs.length - 1 && !this.autoslide) {
18514 if (i >= this.tabs.length - 1 && this.autoslide) {
18518 this.showPanel(this.tabs[i+1]);
18521 showPanelPrev : function()
18523 var i = this.indexOfPanel(this.getActivePanel());
18525 if (i < 1 && !this.autoslide) {
18529 if (i < 1 && this.autoslide) {
18530 i = this.tabs.length;
18533 this.showPanel(this.tabs[i-1]);
18537 addBullet: function()
18539 if(!this.bullets || Roo.isTouch){
18542 var ctr = this.el.select('.carousel-bullets',true).first();
18543 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18544 var bullet = ctr.createChild({
18545 cls : 'bullet bullet-' + i
18546 },ctr.dom.lastChild);
18551 bullet.on('click', (function(e, el, o, ii, t){
18553 e.preventDefault();
18555 this.showPanel(ii);
18557 if(this.autoslide && this.slideFn){
18558 clearInterval(this.slideFn);
18559 this.slideFn = window.setInterval(function() {
18560 _this.showPanelNext();
18564 }).createDelegate(this, [i, bullet], true));
18569 setActiveBullet : function(i)
18575 Roo.each(this.el.select('.bullet', true).elements, function(el){
18576 el.removeClass('selected');
18579 var bullet = this.el.select('.bullet-' + i, true).first();
18585 bullet.addClass('selected');
18596 Roo.apply(Roo.bootstrap.TabGroup, {
18600 * register a Navigation Group
18601 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18603 register : function(navgrp)
18605 this.groups[navgrp.navId] = navgrp;
18609 * fetch a Navigation Group based on the navigation ID
18610 * if one does not exist , it will get created.
18611 * @param {string} the navgroup to add
18612 * @returns {Roo.bootstrap.NavGroup} the navgroup
18614 get: function(navId) {
18615 if (typeof(this.groups[navId]) == 'undefined') {
18616 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18618 return this.groups[navId] ;
18633 * @class Roo.bootstrap.TabPanel
18634 * @extends Roo.bootstrap.Component
18635 * Bootstrap TabPanel class
18636 * @cfg {Boolean} active panel active
18637 * @cfg {String} html panel content
18638 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18639 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18640 * @cfg {String} href click to link..
18644 * Create a new TabPanel
18645 * @param {Object} config The config object
18648 Roo.bootstrap.TabPanel = function(config){
18649 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18653 * Fires when the active status changes
18654 * @param {Roo.bootstrap.TabPanel} this
18655 * @param {Boolean} state the new state
18660 * @event beforedeactivate
18661 * Fires before a tab is de-activated - can be used to do validation on a form.
18662 * @param {Roo.bootstrap.TabPanel} this
18663 * @return {Boolean} false if there is an error
18666 'beforedeactivate': true
18669 this.tabId = this.tabId || Roo.id();
18673 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18681 getAutoCreate : function(){
18686 // item is needed for carousel - not sure if it has any effect otherwise
18687 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18688 html: this.html || ''
18692 cfg.cls += ' active';
18696 cfg.tabId = this.tabId;
18704 initEvents: function()
18706 var p = this.parent();
18708 this.navId = this.navId || p.navId;
18710 if (typeof(this.navId) != 'undefined') {
18711 // not really needed.. but just in case.. parent should be a NavGroup.
18712 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18716 var i = tg.tabs.length - 1;
18718 if(this.active && tg.bullets > 0 && i < tg.bullets){
18719 tg.setActiveBullet(i);
18723 this.el.on('click', this.onClick, this);
18726 this.el.on("touchstart", this.onTouchStart, this);
18727 this.el.on("touchmove", this.onTouchMove, this);
18728 this.el.on("touchend", this.onTouchEnd, this);
18733 onRender : function(ct, position)
18735 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18738 setActive : function(state)
18740 Roo.log("panel - set active " + this.tabId + "=" + state);
18742 this.active = state;
18744 this.el.removeClass('active');
18746 } else if (!this.el.hasClass('active')) {
18747 this.el.addClass('active');
18750 this.fireEvent('changed', this, state);
18753 onClick : function(e)
18755 e.preventDefault();
18757 if(!this.href.length){
18761 window.location.href = this.href;
18770 onTouchStart : function(e)
18772 this.swiping = false;
18774 this.startX = e.browserEvent.touches[0].clientX;
18775 this.startY = e.browserEvent.touches[0].clientY;
18778 onTouchMove : function(e)
18780 this.swiping = true;
18782 this.endX = e.browserEvent.touches[0].clientX;
18783 this.endY = e.browserEvent.touches[0].clientY;
18786 onTouchEnd : function(e)
18793 var tabGroup = this.parent();
18795 if(this.endX > this.startX){ // swiping right
18796 tabGroup.showPanelPrev();
18800 if(this.startX > this.endX){ // swiping left
18801 tabGroup.showPanelNext();
18820 * @class Roo.bootstrap.DateField
18821 * @extends Roo.bootstrap.Input
18822 * Bootstrap DateField class
18823 * @cfg {Number} weekStart default 0
18824 * @cfg {String} viewMode default empty, (months|years)
18825 * @cfg {String} minViewMode default empty, (months|years)
18826 * @cfg {Number} startDate default -Infinity
18827 * @cfg {Number} endDate default Infinity
18828 * @cfg {Boolean} todayHighlight default false
18829 * @cfg {Boolean} todayBtn default false
18830 * @cfg {Boolean} calendarWeeks default false
18831 * @cfg {Object} daysOfWeekDisabled default empty
18832 * @cfg {Boolean} singleMode default false (true | false)
18834 * @cfg {Boolean} keyboardNavigation default true
18835 * @cfg {String} language default en
18838 * Create a new DateField
18839 * @param {Object} config The config object
18842 Roo.bootstrap.DateField = function(config){
18843 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18847 * Fires when this field show.
18848 * @param {Roo.bootstrap.DateField} this
18849 * @param {Mixed} date The date value
18854 * Fires when this field hide.
18855 * @param {Roo.bootstrap.DateField} this
18856 * @param {Mixed} date The date value
18861 * Fires when select a date.
18862 * @param {Roo.bootstrap.DateField} this
18863 * @param {Mixed} date The date value
18867 * @event beforeselect
18868 * Fires when before select a date.
18869 * @param {Roo.bootstrap.DateField} this
18870 * @param {Mixed} date The date value
18872 beforeselect : true
18876 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18879 * @cfg {String} format
18880 * The default date format string which can be overriden for localization support. The format must be
18881 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18885 * @cfg {String} altFormats
18886 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18887 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18889 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18897 todayHighlight : false,
18903 keyboardNavigation: true,
18905 calendarWeeks: false,
18907 startDate: -Infinity,
18911 daysOfWeekDisabled: [],
18915 singleMode : false,
18917 UTCDate: function()
18919 return new Date(Date.UTC.apply(Date, arguments));
18922 UTCToday: function()
18924 var today = new Date();
18925 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18928 getDate: function() {
18929 var d = this.getUTCDate();
18930 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18933 getUTCDate: function() {
18937 setDate: function(d) {
18938 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18941 setUTCDate: function(d) {
18943 this.setValue(this.formatDate(this.date));
18946 onRender: function(ct, position)
18949 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18951 this.language = this.language || 'en';
18952 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18953 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18955 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18956 this.format = this.format || 'm/d/y';
18957 this.isInline = false;
18958 this.isInput = true;
18959 this.component = this.el.select('.add-on', true).first() || false;
18960 this.component = (this.component && this.component.length === 0) ? false : this.component;
18961 this.hasInput = this.component && this.inputEl().length;
18963 if (typeof(this.minViewMode === 'string')) {
18964 switch (this.minViewMode) {
18966 this.minViewMode = 1;
18969 this.minViewMode = 2;
18972 this.minViewMode = 0;
18977 if (typeof(this.viewMode === 'string')) {
18978 switch (this.viewMode) {
18991 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18993 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18995 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18997 this.picker().on('mousedown', this.onMousedown, this);
18998 this.picker().on('click', this.onClick, this);
19000 this.picker().addClass('datepicker-dropdown');
19002 this.startViewMode = this.viewMode;
19004 if(this.singleMode){
19005 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19006 v.setVisibilityMode(Roo.Element.DISPLAY);
19010 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19011 v.setStyle('width', '189px');
19015 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19016 if(!this.calendarWeeks){
19021 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19022 v.attr('colspan', function(i, val){
19023 return parseInt(val) + 1;
19028 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19030 this.setStartDate(this.startDate);
19031 this.setEndDate(this.endDate);
19033 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19040 if(this.isInline) {
19045 picker : function()
19047 return this.pickerEl;
19048 // return this.el.select('.datepicker', true).first();
19051 fillDow: function()
19053 var dowCnt = this.weekStart;
19062 if(this.calendarWeeks){
19070 while (dowCnt < this.weekStart + 7) {
19074 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19078 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19081 fillMonths: function()
19084 var months = this.picker().select('>.datepicker-months td', true).first();
19086 months.dom.innerHTML = '';
19092 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19095 months.createChild(month);
19102 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;
19104 if (this.date < this.startDate) {
19105 this.viewDate = new Date(this.startDate);
19106 } else if (this.date > this.endDate) {
19107 this.viewDate = new Date(this.endDate);
19109 this.viewDate = new Date(this.date);
19117 var d = new Date(this.viewDate),
19118 year = d.getUTCFullYear(),
19119 month = d.getUTCMonth(),
19120 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19121 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19122 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19123 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19124 currentDate = this.date && this.date.valueOf(),
19125 today = this.UTCToday();
19127 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19129 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19131 // this.picker.select('>tfoot th.today').
19132 // .text(dates[this.language].today)
19133 // .toggle(this.todayBtn !== false);
19135 this.updateNavArrows();
19138 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19140 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19142 prevMonth.setUTCDate(day);
19144 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19146 var nextMonth = new Date(prevMonth);
19148 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19150 nextMonth = nextMonth.valueOf();
19152 var fillMonths = false;
19154 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19156 while(prevMonth.valueOf() <= nextMonth) {
19159 if (prevMonth.getUTCDay() === this.weekStart) {
19161 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19169 if(this.calendarWeeks){
19170 // ISO 8601: First week contains first thursday.
19171 // ISO also states week starts on Monday, but we can be more abstract here.
19173 // Start of current week: based on weekstart/current date
19174 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19175 // Thursday of this week
19176 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19177 // First Thursday of year, year from thursday
19178 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19179 // Calendar week: ms between thursdays, div ms per day, div 7 days
19180 calWeek = (th - yth) / 864e5 / 7 + 1;
19182 fillMonths.cn.push({
19190 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19192 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19195 if (this.todayHighlight &&
19196 prevMonth.getUTCFullYear() == today.getFullYear() &&
19197 prevMonth.getUTCMonth() == today.getMonth() &&
19198 prevMonth.getUTCDate() == today.getDate()) {
19199 clsName += ' today';
19202 if (currentDate && prevMonth.valueOf() === currentDate) {
19203 clsName += ' active';
19206 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19207 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19208 clsName += ' disabled';
19211 fillMonths.cn.push({
19213 cls: 'day ' + clsName,
19214 html: prevMonth.getDate()
19217 prevMonth.setDate(prevMonth.getDate()+1);
19220 var currentYear = this.date && this.date.getUTCFullYear();
19221 var currentMonth = this.date && this.date.getUTCMonth();
19223 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19225 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19226 v.removeClass('active');
19228 if(currentYear === year && k === currentMonth){
19229 v.addClass('active');
19232 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19233 v.addClass('disabled');
19239 year = parseInt(year/10, 10) * 10;
19241 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19243 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19246 for (var i = -1; i < 11; i++) {
19247 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19249 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19257 showMode: function(dir)
19260 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19263 Roo.each(this.picker().select('>div',true).elements, function(v){
19264 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19267 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19272 if(this.isInline) {
19276 this.picker().removeClass(['bottom', 'top']);
19278 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19280 * place to the top of element!
19284 this.picker().addClass('top');
19285 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19290 this.picker().addClass('bottom');
19292 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19295 parseDate : function(value)
19297 if(!value || value instanceof Date){
19300 var v = Date.parseDate(value, this.format);
19301 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19302 v = Date.parseDate(value, 'Y-m-d');
19304 if(!v && this.altFormats){
19305 if(!this.altFormatsArray){
19306 this.altFormatsArray = this.altFormats.split("|");
19308 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19309 v = Date.parseDate(value, this.altFormatsArray[i]);
19315 formatDate : function(date, fmt)
19317 return (!date || !(date instanceof Date)) ?
19318 date : date.dateFormat(fmt || this.format);
19321 onFocus : function()
19323 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19327 onBlur : function()
19329 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19331 var d = this.inputEl().getValue();
19338 showPopup : function()
19340 this.picker().show();
19344 this.fireEvent('showpopup', this, this.date);
19347 hidePopup : function()
19349 if(this.isInline) {
19352 this.picker().hide();
19353 this.viewMode = this.startViewMode;
19356 this.fireEvent('hidepopup', this, this.date);
19360 onMousedown: function(e)
19362 e.stopPropagation();
19363 e.preventDefault();
19368 Roo.bootstrap.DateField.superclass.keyup.call(this);
19372 setValue: function(v)
19374 if(this.fireEvent('beforeselect', this, v) !== false){
19375 var d = new Date(this.parseDate(v) ).clearTime();
19377 if(isNaN(d.getTime())){
19378 this.date = this.viewDate = '';
19379 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19383 v = this.formatDate(d);
19385 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19387 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19391 this.fireEvent('select', this, this.date);
19395 getValue: function()
19397 return this.formatDate(this.date);
19400 fireKey: function(e)
19402 if (!this.picker().isVisible()){
19403 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19409 var dateChanged = false,
19411 newDate, newViewDate;
19416 e.preventDefault();
19420 if (!this.keyboardNavigation) {
19423 dir = e.keyCode == 37 ? -1 : 1;
19426 newDate = this.moveYear(this.date, dir);
19427 newViewDate = this.moveYear(this.viewDate, dir);
19428 } else if (e.shiftKey){
19429 newDate = this.moveMonth(this.date, dir);
19430 newViewDate = this.moveMonth(this.viewDate, dir);
19432 newDate = new Date(this.date);
19433 newDate.setUTCDate(this.date.getUTCDate() + dir);
19434 newViewDate = new Date(this.viewDate);
19435 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19437 if (this.dateWithinRange(newDate)){
19438 this.date = newDate;
19439 this.viewDate = newViewDate;
19440 this.setValue(this.formatDate(this.date));
19442 e.preventDefault();
19443 dateChanged = true;
19448 if (!this.keyboardNavigation) {
19451 dir = e.keyCode == 38 ? -1 : 1;
19453 newDate = this.moveYear(this.date, dir);
19454 newViewDate = this.moveYear(this.viewDate, dir);
19455 } else if (e.shiftKey){
19456 newDate = this.moveMonth(this.date, dir);
19457 newViewDate = this.moveMonth(this.viewDate, dir);
19459 newDate = new Date(this.date);
19460 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19461 newViewDate = new Date(this.viewDate);
19462 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19464 if (this.dateWithinRange(newDate)){
19465 this.date = newDate;
19466 this.viewDate = newViewDate;
19467 this.setValue(this.formatDate(this.date));
19469 e.preventDefault();
19470 dateChanged = true;
19474 this.setValue(this.formatDate(this.date));
19476 e.preventDefault();
19479 this.setValue(this.formatDate(this.date));
19493 onClick: function(e)
19495 e.stopPropagation();
19496 e.preventDefault();
19498 var target = e.getTarget();
19500 if(target.nodeName.toLowerCase() === 'i'){
19501 target = Roo.get(target).dom.parentNode;
19504 var nodeName = target.nodeName;
19505 var className = target.className;
19506 var html = target.innerHTML;
19507 //Roo.log(nodeName);
19509 switch(nodeName.toLowerCase()) {
19511 switch(className) {
19517 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19518 switch(this.viewMode){
19520 this.viewDate = this.moveMonth(this.viewDate, dir);
19524 this.viewDate = this.moveYear(this.viewDate, dir);
19530 var date = new Date();
19531 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19533 this.setValue(this.formatDate(this.date));
19540 if (className.indexOf('disabled') < 0) {
19541 this.viewDate.setUTCDate(1);
19542 if (className.indexOf('month') > -1) {
19543 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19545 var year = parseInt(html, 10) || 0;
19546 this.viewDate.setUTCFullYear(year);
19550 if(this.singleMode){
19551 this.setValue(this.formatDate(this.viewDate));
19562 //Roo.log(className);
19563 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19564 var day = parseInt(html, 10) || 1;
19565 var year = this.viewDate.getUTCFullYear(),
19566 month = this.viewDate.getUTCMonth();
19568 if (className.indexOf('old') > -1) {
19575 } else if (className.indexOf('new') > -1) {
19583 //Roo.log([year,month,day]);
19584 this.date = this.UTCDate(year, month, day,0,0,0,0);
19585 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19587 //Roo.log(this.formatDate(this.date));
19588 this.setValue(this.formatDate(this.date));
19595 setStartDate: function(startDate)
19597 this.startDate = startDate || -Infinity;
19598 if (this.startDate !== -Infinity) {
19599 this.startDate = this.parseDate(this.startDate);
19602 this.updateNavArrows();
19605 setEndDate: function(endDate)
19607 this.endDate = endDate || Infinity;
19608 if (this.endDate !== Infinity) {
19609 this.endDate = this.parseDate(this.endDate);
19612 this.updateNavArrows();
19615 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19617 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19618 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19619 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19621 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19622 return parseInt(d, 10);
19625 this.updateNavArrows();
19628 updateNavArrows: function()
19630 if(this.singleMode){
19634 var d = new Date(this.viewDate),
19635 year = d.getUTCFullYear(),
19636 month = d.getUTCMonth();
19638 Roo.each(this.picker().select('.prev', true).elements, function(v){
19640 switch (this.viewMode) {
19643 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19649 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19656 Roo.each(this.picker().select('.next', true).elements, function(v){
19658 switch (this.viewMode) {
19661 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19667 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19675 moveMonth: function(date, dir)
19680 var new_date = new Date(date.valueOf()),
19681 day = new_date.getUTCDate(),
19682 month = new_date.getUTCMonth(),
19683 mag = Math.abs(dir),
19685 dir = dir > 0 ? 1 : -1;
19688 // If going back one month, make sure month is not current month
19689 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19691 return new_date.getUTCMonth() == month;
19693 // If going forward one month, make sure month is as expected
19694 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19696 return new_date.getUTCMonth() != new_month;
19698 new_month = month + dir;
19699 new_date.setUTCMonth(new_month);
19700 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19701 if (new_month < 0 || new_month > 11) {
19702 new_month = (new_month + 12) % 12;
19705 // For magnitudes >1, move one month at a time...
19706 for (var i=0; i<mag; i++) {
19707 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19708 new_date = this.moveMonth(new_date, dir);
19710 // ...then reset the day, keeping it in the new month
19711 new_month = new_date.getUTCMonth();
19712 new_date.setUTCDate(day);
19714 return new_month != new_date.getUTCMonth();
19717 // Common date-resetting loop -- if date is beyond end of month, make it
19720 new_date.setUTCDate(--day);
19721 new_date.setUTCMonth(new_month);
19726 moveYear: function(date, dir)
19728 return this.moveMonth(date, dir*12);
19731 dateWithinRange: function(date)
19733 return date >= this.startDate && date <= this.endDate;
19739 this.picker().remove();
19742 validateValue : function(value)
19744 if(this.getVisibilityEl().hasClass('hidden')){
19748 if(value.length < 1) {
19749 if(this.allowBlank){
19755 if(value.length < this.minLength){
19758 if(value.length > this.maxLength){
19762 var vt = Roo.form.VTypes;
19763 if(!vt[this.vtype](value, this)){
19767 if(typeof this.validator == "function"){
19768 var msg = this.validator(value);
19774 if(this.regex && !this.regex.test(value)){
19778 if(typeof(this.parseDate(value)) == 'undefined'){
19782 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19786 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19796 this.date = this.viewDate = '';
19798 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19803 Roo.apply(Roo.bootstrap.DateField, {
19814 html: '<i class="fa fa-arrow-left"/>'
19824 html: '<i class="fa fa-arrow-right"/>'
19866 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19867 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19868 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19869 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19870 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19883 navFnc: 'FullYear',
19888 navFnc: 'FullYear',
19893 Roo.apply(Roo.bootstrap.DateField, {
19897 cls: 'datepicker dropdown-menu roo-dynamic',
19901 cls: 'datepicker-days',
19905 cls: 'table-condensed',
19907 Roo.bootstrap.DateField.head,
19911 Roo.bootstrap.DateField.footer
19918 cls: 'datepicker-months',
19922 cls: 'table-condensed',
19924 Roo.bootstrap.DateField.head,
19925 Roo.bootstrap.DateField.content,
19926 Roo.bootstrap.DateField.footer
19933 cls: 'datepicker-years',
19937 cls: 'table-condensed',
19939 Roo.bootstrap.DateField.head,
19940 Roo.bootstrap.DateField.content,
19941 Roo.bootstrap.DateField.footer
19960 * @class Roo.bootstrap.TimeField
19961 * @extends Roo.bootstrap.Input
19962 * Bootstrap DateField class
19966 * Create a new TimeField
19967 * @param {Object} config The config object
19970 Roo.bootstrap.TimeField = function(config){
19971 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19975 * Fires when this field show.
19976 * @param {Roo.bootstrap.DateField} thisthis
19977 * @param {Mixed} date The date value
19982 * Fires when this field hide.
19983 * @param {Roo.bootstrap.DateField} this
19984 * @param {Mixed} date The date value
19989 * Fires when select a date.
19990 * @param {Roo.bootstrap.DateField} this
19991 * @param {Mixed} date The date value
19997 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20000 * @cfg {String} format
20001 * The default time format string which can be overriden for localization support. The format must be
20002 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20006 onRender: function(ct, position)
20009 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20011 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20013 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20015 this.pop = this.picker().select('>.datepicker-time',true).first();
20016 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20018 this.picker().on('mousedown', this.onMousedown, this);
20019 this.picker().on('click', this.onClick, this);
20021 this.picker().addClass('datepicker-dropdown');
20026 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20027 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20028 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20029 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20030 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20031 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20035 fireKey: function(e){
20036 if (!this.picker().isVisible()){
20037 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20043 e.preventDefault();
20051 this.onTogglePeriod();
20054 this.onIncrementMinutes();
20057 this.onDecrementMinutes();
20066 onClick: function(e) {
20067 e.stopPropagation();
20068 e.preventDefault();
20071 picker : function()
20073 return this.el.select('.datepicker', true).first();
20076 fillTime: function()
20078 var time = this.pop.select('tbody', true).first();
20080 time.dom.innerHTML = '';
20095 cls: 'hours-up glyphicon glyphicon-chevron-up'
20115 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20136 cls: 'timepicker-hour',
20151 cls: 'timepicker-minute',
20166 cls: 'btn btn-primary period',
20188 cls: 'hours-down glyphicon glyphicon-chevron-down'
20208 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20226 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20233 var hours = this.time.getHours();
20234 var minutes = this.time.getMinutes();
20247 hours = hours - 12;
20251 hours = '0' + hours;
20255 minutes = '0' + minutes;
20258 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20259 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20260 this.pop.select('button', true).first().dom.innerHTML = period;
20266 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20268 var cls = ['bottom'];
20270 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20277 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20282 this.picker().addClass(cls.join('-'));
20286 Roo.each(cls, function(c){
20288 _this.picker().setTop(_this.inputEl().getHeight());
20292 _this.picker().setTop(0 - _this.picker().getHeight());
20297 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20301 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20308 onFocus : function()
20310 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20314 onBlur : function()
20316 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20322 this.picker().show();
20327 this.fireEvent('show', this, this.date);
20332 this.picker().hide();
20335 this.fireEvent('hide', this, this.date);
20338 setTime : function()
20341 this.setValue(this.time.format(this.format));
20343 this.fireEvent('select', this, this.date);
20348 onMousedown: function(e){
20349 e.stopPropagation();
20350 e.preventDefault();
20353 onIncrementHours: function()
20355 Roo.log('onIncrementHours');
20356 this.time = this.time.add(Date.HOUR, 1);
20361 onDecrementHours: function()
20363 Roo.log('onDecrementHours');
20364 this.time = this.time.add(Date.HOUR, -1);
20368 onIncrementMinutes: function()
20370 Roo.log('onIncrementMinutes');
20371 this.time = this.time.add(Date.MINUTE, 1);
20375 onDecrementMinutes: function()
20377 Roo.log('onDecrementMinutes');
20378 this.time = this.time.add(Date.MINUTE, -1);
20382 onTogglePeriod: function()
20384 Roo.log('onTogglePeriod');
20385 this.time = this.time.add(Date.HOUR, 12);
20392 Roo.apply(Roo.bootstrap.TimeField, {
20422 cls: 'btn btn-info ok',
20434 Roo.apply(Roo.bootstrap.TimeField, {
20438 cls: 'datepicker dropdown-menu',
20442 cls: 'datepicker-time',
20446 cls: 'table-condensed',
20448 Roo.bootstrap.TimeField.content,
20449 Roo.bootstrap.TimeField.footer
20468 * @class Roo.bootstrap.MonthField
20469 * @extends Roo.bootstrap.Input
20470 * Bootstrap MonthField class
20472 * @cfg {String} language default en
20475 * Create a new MonthField
20476 * @param {Object} config The config object
20479 Roo.bootstrap.MonthField = function(config){
20480 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20485 * Fires when this field show.
20486 * @param {Roo.bootstrap.MonthField} this
20487 * @param {Mixed} date The date value
20492 * Fires when this field hide.
20493 * @param {Roo.bootstrap.MonthField} this
20494 * @param {Mixed} date The date value
20499 * Fires when select a date.
20500 * @param {Roo.bootstrap.MonthField} this
20501 * @param {String} oldvalue The old value
20502 * @param {String} newvalue The new value
20508 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20510 onRender: function(ct, position)
20513 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20515 this.language = this.language || 'en';
20516 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20517 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20519 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20520 this.isInline = false;
20521 this.isInput = true;
20522 this.component = this.el.select('.add-on', true).first() || false;
20523 this.component = (this.component && this.component.length === 0) ? false : this.component;
20524 this.hasInput = this.component && this.inputEL().length;
20526 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20528 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20530 this.picker().on('mousedown', this.onMousedown, this);
20531 this.picker().on('click', this.onClick, this);
20533 this.picker().addClass('datepicker-dropdown');
20535 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20536 v.setStyle('width', '189px');
20543 if(this.isInline) {
20549 setValue: function(v, suppressEvent)
20551 var o = this.getValue();
20553 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20557 if(suppressEvent !== true){
20558 this.fireEvent('select', this, o, v);
20563 getValue: function()
20568 onClick: function(e)
20570 e.stopPropagation();
20571 e.preventDefault();
20573 var target = e.getTarget();
20575 if(target.nodeName.toLowerCase() === 'i'){
20576 target = Roo.get(target).dom.parentNode;
20579 var nodeName = target.nodeName;
20580 var className = target.className;
20581 var html = target.innerHTML;
20583 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20587 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20589 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20595 picker : function()
20597 return this.pickerEl;
20600 fillMonths: function()
20603 var months = this.picker().select('>.datepicker-months td', true).first();
20605 months.dom.innerHTML = '';
20611 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20614 months.createChild(month);
20623 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20624 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20627 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20628 e.removeClass('active');
20630 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20631 e.addClass('active');
20638 if(this.isInline) {
20642 this.picker().removeClass(['bottom', 'top']);
20644 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20646 * place to the top of element!
20650 this.picker().addClass('top');
20651 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20656 this.picker().addClass('bottom');
20658 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20661 onFocus : function()
20663 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20667 onBlur : function()
20669 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20671 var d = this.inputEl().getValue();
20680 this.picker().show();
20681 this.picker().select('>.datepicker-months', true).first().show();
20685 this.fireEvent('show', this, this.date);
20690 if(this.isInline) {
20693 this.picker().hide();
20694 this.fireEvent('hide', this, this.date);
20698 onMousedown: function(e)
20700 e.stopPropagation();
20701 e.preventDefault();
20706 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20710 fireKey: function(e)
20712 if (!this.picker().isVisible()){
20713 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20724 e.preventDefault();
20728 dir = e.keyCode == 37 ? -1 : 1;
20730 this.vIndex = this.vIndex + dir;
20732 if(this.vIndex < 0){
20736 if(this.vIndex > 11){
20740 if(isNaN(this.vIndex)){
20744 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20750 dir = e.keyCode == 38 ? -1 : 1;
20752 this.vIndex = this.vIndex + dir * 4;
20754 if(this.vIndex < 0){
20758 if(this.vIndex > 11){
20762 if(isNaN(this.vIndex)){
20766 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20771 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20772 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20776 e.preventDefault();
20779 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20780 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20796 this.picker().remove();
20801 Roo.apply(Roo.bootstrap.MonthField, {
20820 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20821 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20826 Roo.apply(Roo.bootstrap.MonthField, {
20830 cls: 'datepicker dropdown-menu roo-dynamic',
20834 cls: 'datepicker-months',
20838 cls: 'table-condensed',
20840 Roo.bootstrap.DateField.content
20860 * @class Roo.bootstrap.CheckBox
20861 * @extends Roo.bootstrap.Input
20862 * Bootstrap CheckBox class
20864 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20865 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20866 * @cfg {String} boxLabel The text that appears beside the checkbox
20867 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20868 * @cfg {Boolean} checked initnal the element
20869 * @cfg {Boolean} inline inline the element (default false)
20870 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20871 * @cfg {String} tooltip label tooltip
20874 * Create a new CheckBox
20875 * @param {Object} config The config object
20878 Roo.bootstrap.CheckBox = function(config){
20879 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20884 * Fires when the element is checked or unchecked.
20885 * @param {Roo.bootstrap.CheckBox} this This input
20886 * @param {Boolean} checked The new checked value
20891 * Fires when the element is click.
20892 * @param {Roo.bootstrap.CheckBox} this This input
20899 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20901 inputType: 'checkbox',
20910 // checkbox success does not make any sense really..
20915 getAutoCreate : function()
20917 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20923 cfg.cls = 'form-group ' + this.inputType; //input-group
20926 cfg.cls += ' ' + this.inputType + '-inline';
20932 type : this.inputType,
20933 value : this.inputValue,
20934 cls : 'roo-' + this.inputType, //'form-box',
20935 placeholder : this.placeholder || ''
20939 if(this.inputType != 'radio'){
20943 cls : 'roo-hidden-value',
20944 value : this.checked ? this.inputValue : this.valueOff
20949 if (this.weight) { // Validity check?
20950 cfg.cls += " " + this.inputType + "-" + this.weight;
20953 if (this.disabled) {
20954 input.disabled=true;
20958 input.checked = this.checked;
20963 input.name = this.name;
20965 if(this.inputType != 'radio'){
20966 hidden.name = this.name;
20967 input.name = '_hidden_' + this.name;
20972 input.cls += ' input-' + this.size;
20977 ['xs','sm','md','lg'].map(function(size){
20978 if (settings[size]) {
20979 cfg.cls += ' col-' + size + '-' + settings[size];
20983 var inputblock = input;
20985 if (this.before || this.after) {
20988 cls : 'input-group',
20993 inputblock.cn.push({
20995 cls : 'input-group-addon',
21000 inputblock.cn.push(input);
21002 if(this.inputType != 'radio'){
21003 inputblock.cn.push(hidden);
21007 inputblock.cn.push({
21009 cls : 'input-group-addon',
21015 var boxLabelCfg = false;
21021 //'for': id, // box label is handled by onclick - so no for...
21023 html: this.boxLabel
21026 boxLabelCfg.tooltip = this.tooltip;
21032 if (align ==='left' && this.fieldLabel.length) {
21033 // Roo.log("left and has label");
21038 cls : 'control-label',
21039 html : this.fieldLabel
21050 cfg.cn[1].cn.push(boxLabelCfg);
21053 if(this.labelWidth > 12){
21054 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21057 if(this.labelWidth < 13 && this.labelmd == 0){
21058 this.labelmd = this.labelWidth;
21061 if(this.labellg > 0){
21062 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21063 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21066 if(this.labelmd > 0){
21067 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21068 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21071 if(this.labelsm > 0){
21072 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21073 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21076 if(this.labelxs > 0){
21077 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21078 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21081 } else if ( this.fieldLabel.length) {
21082 // Roo.log(" label");
21086 tag: this.boxLabel ? 'span' : 'label',
21088 cls: 'control-label box-input-label',
21089 //cls : 'input-group-addon',
21090 html : this.fieldLabel
21097 cfg.cn.push(boxLabelCfg);
21102 // Roo.log(" no label && no align");
21103 cfg.cn = [ inputblock ] ;
21105 cfg.cn.push(boxLabelCfg);
21113 if(this.inputType != 'radio'){
21114 cfg.cn.push(hidden);
21122 * return the real input element.
21124 inputEl: function ()
21126 return this.el.select('input.roo-' + this.inputType,true).first();
21128 hiddenEl: function ()
21130 return this.el.select('input.roo-hidden-value',true).first();
21133 labelEl: function()
21135 return this.el.select('label.control-label',true).first();
21137 /* depricated... */
21141 return this.labelEl();
21144 boxLabelEl: function()
21146 return this.el.select('label.box-label',true).first();
21149 initEvents : function()
21151 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21153 this.inputEl().on('click', this.onClick, this);
21155 if (this.boxLabel) {
21156 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21159 this.startValue = this.getValue();
21162 Roo.bootstrap.CheckBox.register(this);
21166 onClick : function(e)
21168 if(this.fireEvent('click', this, e) !== false){
21169 this.setChecked(!this.checked);
21174 setChecked : function(state,suppressEvent)
21176 this.startValue = this.getValue();
21178 if(this.inputType == 'radio'){
21180 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21181 e.dom.checked = false;
21184 this.inputEl().dom.checked = true;
21186 this.inputEl().dom.value = this.inputValue;
21188 if(suppressEvent !== true){
21189 this.fireEvent('check', this, true);
21197 this.checked = state;
21199 this.inputEl().dom.checked = state;
21202 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21204 if(suppressEvent !== true){
21205 this.fireEvent('check', this, state);
21211 getValue : function()
21213 if(this.inputType == 'radio'){
21214 return this.getGroupValue();
21217 return this.hiddenEl().dom.value;
21221 getGroupValue : function()
21223 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21227 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21230 setValue : function(v,suppressEvent)
21232 if(this.inputType == 'radio'){
21233 this.setGroupValue(v, suppressEvent);
21237 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21242 setGroupValue : function(v, suppressEvent)
21244 this.startValue = this.getValue();
21246 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21247 e.dom.checked = false;
21249 if(e.dom.value == v){
21250 e.dom.checked = true;
21254 if(suppressEvent !== true){
21255 this.fireEvent('check', this, true);
21263 validate : function()
21265 if(this.getVisibilityEl().hasClass('hidden')){
21271 (this.inputType == 'radio' && this.validateRadio()) ||
21272 (this.inputType == 'checkbox' && this.validateCheckbox())
21278 this.markInvalid();
21282 validateRadio : function()
21284 if(this.getVisibilityEl().hasClass('hidden')){
21288 if(this.allowBlank){
21294 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21295 if(!e.dom.checked){
21307 validateCheckbox : function()
21310 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21311 //return (this.getValue() == this.inputValue) ? true : false;
21314 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21322 for(var i in group){
21323 if(group[i].el.isVisible(true)){
21331 for(var i in group){
21336 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21343 * Mark this field as valid
21345 markValid : function()
21349 this.fireEvent('valid', this);
21351 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21354 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21361 if(this.inputType == 'radio'){
21362 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21363 var fg = e.findParent('.form-group', false, true);
21364 if (Roo.bootstrap.version == 3) {
21365 fg.removeClass([_this.invalidClass, _this.validClass]);
21366 fg.addClass(_this.validClass);
21368 fg.removeClass(['is-valid', 'is-invalid']);
21369 fg.addClass('is-valid');
21377 var fg = this.el.findParent('.form-group', false, true);
21378 if (Roo.bootstrap.version == 3) {
21379 fg.removeClass([this.invalidClass, this.validClass]);
21380 fg.addClass(this.validClass);
21382 fg.removeClass(['is-valid', 'is-invalid']);
21383 fg.addClass('is-valid');
21388 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21394 for(var i in group){
21395 var fg = group[i].el.findParent('.form-group', false, true);
21396 if (Roo.bootstrap.version == 3) {
21397 fg.removeClass([this.invalidClass, this.validClass]);
21398 fg.addClass(this.validClass);
21400 fg.removeClass(['is-valid', 'is-invalid']);
21401 fg.addClass('is-valid');
21407 * Mark this field as invalid
21408 * @param {String} msg The validation message
21410 markInvalid : function(msg)
21412 if(this.allowBlank){
21418 this.fireEvent('invalid', this, msg);
21420 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21423 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21427 label.markInvalid();
21430 if(this.inputType == 'radio'){
21432 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21433 var fg = e.findParent('.form-group', false, true);
21434 if (Roo.bootstrap.version == 3) {
21435 fg.removeClass([_this.invalidClass, _this.validClass]);
21436 fg.addClass(_this.invalidClass);
21438 fg.removeClass(['is-invalid', 'is-valid']);
21439 fg.addClass('is-invalid');
21447 var fg = this.el.findParent('.form-group', false, true);
21448 if (Roo.bootstrap.version == 3) {
21449 fg.removeClass([_this.invalidClass, _this.validClass]);
21450 fg.addClass(_this.invalidClass);
21452 fg.removeClass(['is-invalid', 'is-valid']);
21453 fg.addClass('is-invalid');
21458 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21464 for(var i in group){
21465 var fg = group[i].el.findParent('.form-group', false, true);
21466 if (Roo.bootstrap.version == 3) {
21467 fg.removeClass([_this.invalidClass, _this.validClass]);
21468 fg.addClass(_this.invalidClass);
21470 fg.removeClass(['is-invalid', 'is-valid']);
21471 fg.addClass('is-invalid');
21477 clearInvalid : function()
21479 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21481 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21483 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21485 if (label && label.iconEl) {
21486 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21487 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21491 disable : function()
21493 if(this.inputType != 'radio'){
21494 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21501 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21502 _this.getActionEl().addClass(this.disabledClass);
21503 e.dom.disabled = true;
21507 this.disabled = true;
21508 this.fireEvent("disable", this);
21512 enable : function()
21514 if(this.inputType != 'radio'){
21515 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21522 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21523 _this.getActionEl().removeClass(this.disabledClass);
21524 e.dom.disabled = false;
21528 this.disabled = false;
21529 this.fireEvent("enable", this);
21533 setBoxLabel : function(v)
21538 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21544 Roo.apply(Roo.bootstrap.CheckBox, {
21549 * register a CheckBox Group
21550 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21552 register : function(checkbox)
21554 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21555 this.groups[checkbox.groupId] = {};
21558 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21562 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21566 * fetch a CheckBox Group based on the group ID
21567 * @param {string} the group ID
21568 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21570 get: function(groupId) {
21571 if (typeof(this.groups[groupId]) == 'undefined') {
21575 return this.groups[groupId] ;
21588 * @class Roo.bootstrap.Radio
21589 * @extends Roo.bootstrap.Component
21590 * Bootstrap Radio class
21591 * @cfg {String} boxLabel - the label associated
21592 * @cfg {String} value - the value of radio
21595 * Create a new Radio
21596 * @param {Object} config The config object
21598 Roo.bootstrap.Radio = function(config){
21599 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21603 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21609 getAutoCreate : function()
21613 cls : 'form-group radio',
21618 html : this.boxLabel
21626 initEvents : function()
21628 this.parent().register(this);
21630 this.el.on('click', this.onClick, this);
21634 onClick : function(e)
21636 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21637 this.setChecked(true);
21641 setChecked : function(state, suppressEvent)
21643 this.parent().setValue(this.value, suppressEvent);
21647 setBoxLabel : function(v)
21652 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21667 * @class Roo.bootstrap.SecurePass
21668 * @extends Roo.bootstrap.Input
21669 * Bootstrap SecurePass class
21673 * Create a new SecurePass
21674 * @param {Object} config The config object
21677 Roo.bootstrap.SecurePass = function (config) {
21678 // these go here, so the translation tool can replace them..
21680 PwdEmpty: "Please type a password, and then retype it to confirm.",
21681 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21682 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21683 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21684 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21685 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21686 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21687 TooWeak: "Your password is Too Weak."
21689 this.meterLabel = "Password strength:";
21690 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21691 this.meterClass = [
21692 "roo-password-meter-tooweak",
21693 "roo-password-meter-weak",
21694 "roo-password-meter-medium",
21695 "roo-password-meter-strong",
21696 "roo-password-meter-grey"
21701 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21704 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21706 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21708 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21709 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21710 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21711 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21712 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21713 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21714 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21724 * @cfg {String/Object} Label for the strength meter (defaults to
21725 * 'Password strength:')
21730 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21731 * ['Weak', 'Medium', 'Strong'])
21734 pwdStrengths: false,
21747 initEvents: function ()
21749 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21751 if (this.el.is('input[type=password]') && Roo.isSafari) {
21752 this.el.on('keydown', this.SafariOnKeyDown, this);
21755 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21758 onRender: function (ct, position)
21760 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21761 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21762 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21764 this.trigger.createChild({
21769 cls: 'roo-password-meter-grey col-xs-12',
21772 //width: this.meterWidth + 'px'
21776 cls: 'roo-password-meter-text'
21782 if (this.hideTrigger) {
21783 this.trigger.setDisplayed(false);
21785 this.setSize(this.width || '', this.height || '');
21788 onDestroy: function ()
21790 if (this.trigger) {
21791 this.trigger.removeAllListeners();
21792 this.trigger.remove();
21795 this.wrap.remove();
21797 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21800 checkStrength: function ()
21802 var pwd = this.inputEl().getValue();
21803 if (pwd == this._lastPwd) {
21808 if (this.ClientSideStrongPassword(pwd)) {
21810 } else if (this.ClientSideMediumPassword(pwd)) {
21812 } else if (this.ClientSideWeakPassword(pwd)) {
21818 Roo.log('strength1: ' + strength);
21820 //var pm = this.trigger.child('div/div/div').dom;
21821 var pm = this.trigger.child('div/div');
21822 pm.removeClass(this.meterClass);
21823 pm.addClass(this.meterClass[strength]);
21826 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21828 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21830 this._lastPwd = pwd;
21834 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21836 this._lastPwd = '';
21838 var pm = this.trigger.child('div/div');
21839 pm.removeClass(this.meterClass);
21840 pm.addClass('roo-password-meter-grey');
21843 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21846 this.inputEl().dom.type='password';
21849 validateValue: function (value)
21852 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21855 if (value.length == 0) {
21856 if (this.allowBlank) {
21857 this.clearInvalid();
21861 this.markInvalid(this.errors.PwdEmpty);
21862 this.errorMsg = this.errors.PwdEmpty;
21870 if ('[\x21-\x7e]*'.match(value)) {
21871 this.markInvalid(this.errors.PwdBadChar);
21872 this.errorMsg = this.errors.PwdBadChar;
21875 if (value.length < 6) {
21876 this.markInvalid(this.errors.PwdShort);
21877 this.errorMsg = this.errors.PwdShort;
21880 if (value.length > 16) {
21881 this.markInvalid(this.errors.PwdLong);
21882 this.errorMsg = this.errors.PwdLong;
21886 if (this.ClientSideStrongPassword(value)) {
21888 } else if (this.ClientSideMediumPassword(value)) {
21890 } else if (this.ClientSideWeakPassword(value)) {
21897 if (strength < 2) {
21898 //this.markInvalid(this.errors.TooWeak);
21899 this.errorMsg = this.errors.TooWeak;
21904 console.log('strength2: ' + strength);
21906 //var pm = this.trigger.child('div/div/div').dom;
21908 var pm = this.trigger.child('div/div');
21909 pm.removeClass(this.meterClass);
21910 pm.addClass(this.meterClass[strength]);
21912 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21914 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21916 this.errorMsg = '';
21920 CharacterSetChecks: function (type)
21923 this.fResult = false;
21926 isctype: function (character, type)
21929 case this.kCapitalLetter:
21930 if (character >= 'A' && character <= 'Z') {
21935 case this.kSmallLetter:
21936 if (character >= 'a' && character <= 'z') {
21942 if (character >= '0' && character <= '9') {
21947 case this.kPunctuation:
21948 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21959 IsLongEnough: function (pwd, size)
21961 return !(pwd == null || isNaN(size) || pwd.length < size);
21964 SpansEnoughCharacterSets: function (word, nb)
21966 if (!this.IsLongEnough(word, nb))
21971 var characterSetChecks = new Array(
21972 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21973 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21976 for (var index = 0; index < word.length; ++index) {
21977 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21978 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21979 characterSetChecks[nCharSet].fResult = true;
21986 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21987 if (characterSetChecks[nCharSet].fResult) {
21992 if (nCharSets < nb) {
21998 ClientSideStrongPassword: function (pwd)
22000 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
22003 ClientSideMediumPassword: function (pwd)
22005 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22008 ClientSideWeakPassword: function (pwd)
22010 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22013 })//<script type="text/javascript">
22016 * Based Ext JS Library 1.1.1
22017 * Copyright(c) 2006-2007, Ext JS, LLC.
22023 * @class Roo.HtmlEditorCore
22024 * @extends Roo.Component
22025 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22027 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22030 Roo.HtmlEditorCore = function(config){
22033 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22038 * @event initialize
22039 * Fires when the editor is fully initialized (including the iframe)
22040 * @param {Roo.HtmlEditorCore} this
22045 * Fires when the editor is first receives the focus. Any insertion must wait
22046 * until after this event.
22047 * @param {Roo.HtmlEditorCore} this
22051 * @event beforesync
22052 * Fires before the textarea is updated with content from the editor iframe. Return false
22053 * to cancel the sync.
22054 * @param {Roo.HtmlEditorCore} this
22055 * @param {String} html
22059 * @event beforepush
22060 * Fires before the iframe editor is updated with content from the textarea. Return false
22061 * to cancel the push.
22062 * @param {Roo.HtmlEditorCore} this
22063 * @param {String} html
22068 * Fires when the textarea is updated with content from the editor iframe.
22069 * @param {Roo.HtmlEditorCore} this
22070 * @param {String} html
22075 * Fires when the iframe editor is updated with content from the textarea.
22076 * @param {Roo.HtmlEditorCore} this
22077 * @param {String} html
22082 * @event editorevent
22083 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22084 * @param {Roo.HtmlEditorCore} this
22090 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22092 // defaults : white / black...
22093 this.applyBlacklists();
22100 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22104 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22110 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22115 * @cfg {Number} height (in pixels)
22119 * @cfg {Number} width (in pixels)
22124 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22127 stylesheets: false,
22132 // private properties
22133 validationEvent : false,
22135 initialized : false,
22137 sourceEditMode : false,
22138 onFocus : Roo.emptyFn,
22140 hideMode:'offsets',
22144 // blacklist + whitelisted elements..
22151 * Protected method that will not generally be called directly. It
22152 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22153 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22155 getDocMarkup : function(){
22159 // inherit styels from page...??
22160 if (this.stylesheets === false) {
22162 Roo.get(document.head).select('style').each(function(node) {
22163 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22166 Roo.get(document.head).select('link').each(function(node) {
22167 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22170 } else if (!this.stylesheets.length) {
22172 st = '<style type="text/css">' +
22173 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22176 st = '<style type="text/css">' +
22181 st += '<style type="text/css">' +
22182 'IMG { cursor: pointer } ' +
22185 var cls = 'roo-htmleditor-body';
22187 if(this.bodyCls.length){
22188 cls += ' ' + this.bodyCls;
22191 return '<html><head>' + st +
22192 //<style type="text/css">' +
22193 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22195 ' </head><body class="' + cls + '"></body></html>';
22199 onRender : function(ct, position)
22202 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22203 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22206 this.el.dom.style.border = '0 none';
22207 this.el.dom.setAttribute('tabIndex', -1);
22208 this.el.addClass('x-hidden hide');
22212 if(Roo.isIE){ // fix IE 1px bogus margin
22213 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22217 this.frameId = Roo.id();
22221 var iframe = this.owner.wrap.createChild({
22223 cls: 'form-control', // bootstrap..
22225 name: this.frameId,
22226 frameBorder : 'no',
22227 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22232 this.iframe = iframe.dom;
22234 this.assignDocWin();
22236 this.doc.designMode = 'on';
22239 this.doc.write(this.getDocMarkup());
22243 var task = { // must defer to wait for browser to be ready
22245 //console.log("run task?" + this.doc.readyState);
22246 this.assignDocWin();
22247 if(this.doc.body || this.doc.readyState == 'complete'){
22249 this.doc.designMode="on";
22253 Roo.TaskMgr.stop(task);
22254 this.initEditor.defer(10, this);
22261 Roo.TaskMgr.start(task);
22266 onResize : function(w, h)
22268 Roo.log('resize: ' +w + ',' + h );
22269 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22273 if(typeof w == 'number'){
22275 this.iframe.style.width = w + 'px';
22277 if(typeof h == 'number'){
22279 this.iframe.style.height = h + 'px';
22281 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22288 * Toggles the editor between standard and source edit mode.
22289 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22291 toggleSourceEdit : function(sourceEditMode){
22293 this.sourceEditMode = sourceEditMode === true;
22295 if(this.sourceEditMode){
22297 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22300 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22301 //this.iframe.className = '';
22304 //this.setSize(this.owner.wrap.getSize());
22305 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22312 * Protected method that will not generally be called directly. If you need/want
22313 * custom HTML cleanup, this is the method you should override.
22314 * @param {String} html The HTML to be cleaned
22315 * return {String} The cleaned HTML
22317 cleanHtml : function(html){
22318 html = String(html);
22319 if(html.length > 5){
22320 if(Roo.isSafari){ // strip safari nonsense
22321 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22324 if(html == ' '){
22331 * HTML Editor -> Textarea
22332 * Protected method that will not generally be called directly. Syncs the contents
22333 * of the editor iframe with the textarea.
22335 syncValue : function(){
22336 if(this.initialized){
22337 var bd = (this.doc.body || this.doc.documentElement);
22338 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22339 var html = bd.innerHTML;
22341 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22342 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22344 html = '<div style="'+m[0]+'">' + html + '</div>';
22347 html = this.cleanHtml(html);
22348 // fix up the special chars.. normaly like back quotes in word...
22349 // however we do not want to do this with chinese..
22350 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
22352 var cc = match.charCodeAt();
22354 // Get the character value, handling surrogate pairs
22355 if (match.length == 2) {
22356 // It's a surrogate pair, calculate the Unicode code point
22357 var high = match.charCodeAt(0) - 0xD800;
22358 var low = match.charCodeAt(1) - 0xDC00;
22359 cc = (high * 0x400) + low + 0x10000;
22361 (cc >= 0x4E00 && cc < 0xA000 ) ||
22362 (cc >= 0x3400 && cc < 0x4E00 ) ||
22363 (cc >= 0xf900 && cc < 0xfb00 )
22368 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
22369 return "&#" + cc + ";";
22376 if(this.owner.fireEvent('beforesync', this, html) !== false){
22377 this.el.dom.value = html;
22378 this.owner.fireEvent('sync', this, html);
22384 * Protected method that will not generally be called directly. Pushes the value of the textarea
22385 * into the iframe editor.
22387 pushValue : function(){
22388 if(this.initialized){
22389 var v = this.el.dom.value.trim();
22391 // if(v.length < 1){
22395 if(this.owner.fireEvent('beforepush', this, v) !== false){
22396 var d = (this.doc.body || this.doc.documentElement);
22398 this.cleanUpPaste();
22399 this.el.dom.value = d.innerHTML;
22400 this.owner.fireEvent('push', this, v);
22406 deferFocus : function(){
22407 this.focus.defer(10, this);
22411 focus : function(){
22412 if(this.win && !this.sourceEditMode){
22419 assignDocWin: function()
22421 var iframe = this.iframe;
22424 this.doc = iframe.contentWindow.document;
22425 this.win = iframe.contentWindow;
22427 // if (!Roo.get(this.frameId)) {
22430 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22431 // this.win = Roo.get(this.frameId).dom.contentWindow;
22433 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22437 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22438 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22443 initEditor : function(){
22444 //console.log("INIT EDITOR");
22445 this.assignDocWin();
22449 this.doc.designMode="on";
22451 this.doc.write(this.getDocMarkup());
22454 var dbody = (this.doc.body || this.doc.documentElement);
22455 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22456 // this copies styles from the containing element into thsi one..
22457 // not sure why we need all of this..
22458 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22460 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22461 //ss['background-attachment'] = 'fixed'; // w3c
22462 dbody.bgProperties = 'fixed'; // ie
22463 //Roo.DomHelper.applyStyles(dbody, ss);
22464 Roo.EventManager.on(this.doc, {
22465 //'mousedown': this.onEditorEvent,
22466 'mouseup': this.onEditorEvent,
22467 'dblclick': this.onEditorEvent,
22468 'click': this.onEditorEvent,
22469 'keyup': this.onEditorEvent,
22474 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22476 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22477 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22479 this.initialized = true;
22481 this.owner.fireEvent('initialize', this);
22486 onDestroy : function(){
22492 //for (var i =0; i < this.toolbars.length;i++) {
22493 // // fixme - ask toolbars for heights?
22494 // this.toolbars[i].onDestroy();
22497 //this.wrap.dom.innerHTML = '';
22498 //this.wrap.remove();
22503 onFirstFocus : function(){
22505 this.assignDocWin();
22508 this.activated = true;
22511 if(Roo.isGecko){ // prevent silly gecko errors
22513 var s = this.win.getSelection();
22514 if(!s.focusNode || s.focusNode.nodeType != 3){
22515 var r = s.getRangeAt(0);
22516 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22521 this.execCmd('useCSS', true);
22522 this.execCmd('styleWithCSS', false);
22525 this.owner.fireEvent('activate', this);
22529 adjustFont: function(btn){
22530 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22531 //if(Roo.isSafari){ // safari
22534 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22535 if(Roo.isSafari){ // safari
22536 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22537 v = (v < 10) ? 10 : v;
22538 v = (v > 48) ? 48 : v;
22539 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22544 v = Math.max(1, v+adjust);
22546 this.execCmd('FontSize', v );
22549 onEditorEvent : function(e)
22551 this.owner.fireEvent('editorevent', this, e);
22552 // this.updateToolbar();
22553 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22556 insertTag : function(tg)
22558 // could be a bit smarter... -> wrap the current selected tRoo..
22559 if (tg.toLowerCase() == 'span' ||
22560 tg.toLowerCase() == 'code' ||
22561 tg.toLowerCase() == 'sup' ||
22562 tg.toLowerCase() == 'sub'
22565 range = this.createRange(this.getSelection());
22566 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22567 wrappingNode.appendChild(range.extractContents());
22568 range.insertNode(wrappingNode);
22575 this.execCmd("formatblock", tg);
22579 insertText : function(txt)
22583 var range = this.createRange();
22584 range.deleteContents();
22585 //alert(Sender.getAttribute('label'));
22587 range.insertNode(this.doc.createTextNode(txt));
22593 * Executes a Midas editor command on the editor document and performs necessary focus and
22594 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22595 * @param {String} cmd The Midas command
22596 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22598 relayCmd : function(cmd, value){
22600 this.execCmd(cmd, value);
22601 this.owner.fireEvent('editorevent', this);
22602 //this.updateToolbar();
22603 this.owner.deferFocus();
22607 * Executes a Midas editor command directly on the editor document.
22608 * For visual commands, you should use {@link #relayCmd} instead.
22609 * <b>This should only be called after the editor is initialized.</b>
22610 * @param {String} cmd The Midas command
22611 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22613 execCmd : function(cmd, value){
22614 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22621 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22623 * @param {String} text | dom node..
22625 insertAtCursor : function(text)
22628 if(!this.activated){
22634 var r = this.doc.selection.createRange();
22645 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22649 // from jquery ui (MIT licenced)
22651 var win = this.win;
22653 if (win.getSelection && win.getSelection().getRangeAt) {
22654 range = win.getSelection().getRangeAt(0);
22655 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22656 range.insertNode(node);
22657 } else if (win.document.selection && win.document.selection.createRange) {
22658 // no firefox support
22659 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22660 win.document.selection.createRange().pasteHTML(txt);
22662 // no firefox support
22663 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22664 this.execCmd('InsertHTML', txt);
22673 mozKeyPress : function(e){
22675 var c = e.getCharCode(), cmd;
22678 c = String.fromCharCode(c).toLowerCase();
22692 this.cleanUpPaste.defer(100, this);
22700 e.preventDefault();
22708 fixKeys : function(){ // load time branching for fastest keydown performance
22710 return function(e){
22711 var k = e.getKey(), r;
22714 r = this.doc.selection.createRange();
22717 r.pasteHTML('    ');
22724 r = this.doc.selection.createRange();
22726 var target = r.parentElement();
22727 if(!target || target.tagName.toLowerCase() != 'li'){
22729 r.pasteHTML('<br />');
22735 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22736 this.cleanUpPaste.defer(100, this);
22742 }else if(Roo.isOpera){
22743 return function(e){
22744 var k = e.getKey();
22748 this.execCmd('InsertHTML','    ');
22751 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22752 this.cleanUpPaste.defer(100, this);
22757 }else if(Roo.isSafari){
22758 return function(e){
22759 var k = e.getKey();
22763 this.execCmd('InsertText','\t');
22767 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22768 this.cleanUpPaste.defer(100, this);
22776 getAllAncestors: function()
22778 var p = this.getSelectedNode();
22781 a.push(p); // push blank onto stack..
22782 p = this.getParentElement();
22786 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22790 a.push(this.doc.body);
22794 lastSelNode : false,
22797 getSelection : function()
22799 this.assignDocWin();
22800 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22803 getSelectedNode: function()
22805 // this may only work on Gecko!!!
22807 // should we cache this!!!!
22812 var range = this.createRange(this.getSelection()).cloneRange();
22815 var parent = range.parentElement();
22817 var testRange = range.duplicate();
22818 testRange.moveToElementText(parent);
22819 if (testRange.inRange(range)) {
22822 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22825 parent = parent.parentElement;
22830 // is ancestor a text element.
22831 var ac = range.commonAncestorContainer;
22832 if (ac.nodeType == 3) {
22833 ac = ac.parentNode;
22836 var ar = ac.childNodes;
22839 var other_nodes = [];
22840 var has_other_nodes = false;
22841 for (var i=0;i<ar.length;i++) {
22842 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22845 // fullly contained node.
22847 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22852 // probably selected..
22853 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22854 other_nodes.push(ar[i]);
22858 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22863 has_other_nodes = true;
22865 if (!nodes.length && other_nodes.length) {
22866 nodes= other_nodes;
22868 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22874 createRange: function(sel)
22876 // this has strange effects when using with
22877 // top toolbar - not sure if it's a great idea.
22878 //this.editor.contentWindow.focus();
22879 if (typeof sel != "undefined") {
22881 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22883 return this.doc.createRange();
22886 return this.doc.createRange();
22889 getParentElement: function()
22892 this.assignDocWin();
22893 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22895 var range = this.createRange(sel);
22898 var p = range.commonAncestorContainer;
22899 while (p.nodeType == 3) { // text node
22910 * Range intersection.. the hard stuff...
22914 * [ -- selected range --- ]
22918 * if end is before start or hits it. fail.
22919 * if start is after end or hits it fail.
22921 * if either hits (but other is outside. - then it's not
22927 // @see http://www.thismuchiknow.co.uk/?p=64.
22928 rangeIntersectsNode : function(range, node)
22930 var nodeRange = node.ownerDocument.createRange();
22932 nodeRange.selectNode(node);
22934 nodeRange.selectNodeContents(node);
22937 var rangeStartRange = range.cloneRange();
22938 rangeStartRange.collapse(true);
22940 var rangeEndRange = range.cloneRange();
22941 rangeEndRange.collapse(false);
22943 var nodeStartRange = nodeRange.cloneRange();
22944 nodeStartRange.collapse(true);
22946 var nodeEndRange = nodeRange.cloneRange();
22947 nodeEndRange.collapse(false);
22949 return rangeStartRange.compareBoundaryPoints(
22950 Range.START_TO_START, nodeEndRange) == -1 &&
22951 rangeEndRange.compareBoundaryPoints(
22952 Range.START_TO_START, nodeStartRange) == 1;
22956 rangeCompareNode : function(range, node)
22958 var nodeRange = node.ownerDocument.createRange();
22960 nodeRange.selectNode(node);
22962 nodeRange.selectNodeContents(node);
22966 range.collapse(true);
22968 nodeRange.collapse(true);
22970 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22971 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22973 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22975 var nodeIsBefore = ss == 1;
22976 var nodeIsAfter = ee == -1;
22978 if (nodeIsBefore && nodeIsAfter) {
22981 if (!nodeIsBefore && nodeIsAfter) {
22982 return 1; //right trailed.
22985 if (nodeIsBefore && !nodeIsAfter) {
22986 return 2; // left trailed.
22992 // private? - in a new class?
22993 cleanUpPaste : function()
22995 // cleans up the whole document..
22996 Roo.log('cleanuppaste');
22998 this.cleanUpChildren(this.doc.body);
22999 var clean = this.cleanWordChars(this.doc.body.innerHTML);
23000 if (clean != this.doc.body.innerHTML) {
23001 this.doc.body.innerHTML = clean;
23006 cleanWordChars : function(input) {// change the chars to hex code
23007 var he = Roo.HtmlEditorCore;
23009 var output = input;
23010 Roo.each(he.swapCodes, function(sw) {
23011 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
23013 output = output.replace(swapper, sw[1]);
23020 cleanUpChildren : function (n)
23022 if (!n.childNodes.length) {
23025 for (var i = n.childNodes.length-1; i > -1 ; i--) {
23026 this.cleanUpChild(n.childNodes[i]);
23033 cleanUpChild : function (node)
23036 //console.log(node);
23037 if (node.nodeName == "#text") {
23038 // clean up silly Windows -- stuff?
23041 if (node.nodeName == "#comment") {
23042 node.parentNode.removeChild(node);
23043 // clean up silly Windows -- stuff?
23046 var lcname = node.tagName.toLowerCase();
23047 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23048 // whitelist of tags..
23050 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23052 node.parentNode.removeChild(node);
23057 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23059 // spans with no attributes - just remove them..
23060 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
23061 remove_keep_children = true;
23064 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23065 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23067 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23068 // remove_keep_children = true;
23071 if (remove_keep_children) {
23072 this.cleanUpChildren(node);
23073 // inserts everything just before this node...
23074 while (node.childNodes.length) {
23075 var cn = node.childNodes[0];
23076 node.removeChild(cn);
23077 node.parentNode.insertBefore(cn, node);
23079 node.parentNode.removeChild(node);
23083 if (!node.attributes || !node.attributes.length) {
23088 this.cleanUpChildren(node);
23092 function cleanAttr(n,v)
23095 if (v.match(/^\./) || v.match(/^\//)) {
23098 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23101 if (v.match(/^#/)) {
23104 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23105 node.removeAttribute(n);
23109 var cwhite = this.cwhite;
23110 var cblack = this.cblack;
23112 function cleanStyle(n,v)
23114 if (v.match(/expression/)) { //XSS?? should we even bother..
23115 node.removeAttribute(n);
23119 var parts = v.split(/;/);
23122 Roo.each(parts, function(p) {
23123 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23127 var l = p.split(':').shift().replace(/\s+/g,'');
23128 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23130 if ( cwhite.length && cblack.indexOf(l) > -1) {
23131 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23132 //node.removeAttribute(n);
23136 // only allow 'c whitelisted system attributes'
23137 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23138 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23139 //node.removeAttribute(n);
23149 if (clean.length) {
23150 node.setAttribute(n, clean.join(';'));
23152 node.removeAttribute(n);
23158 for (var i = node.attributes.length-1; i > -1 ; i--) {
23159 var a = node.attributes[i];
23162 if (a.name.toLowerCase().substr(0,2)=='on') {
23163 node.removeAttribute(a.name);
23166 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23167 node.removeAttribute(a.name);
23170 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23171 cleanAttr(a.name,a.value); // fixme..
23174 if (a.name == 'style') {
23175 cleanStyle(a.name,a.value);
23178 /// clean up MS crap..
23179 // tecnically this should be a list of valid class'es..
23182 if (a.name == 'class') {
23183 if (a.value.match(/^Mso/)) {
23184 node.removeAttribute('class');
23187 if (a.value.match(/^body$/)) {
23188 node.removeAttribute('class');
23199 this.cleanUpChildren(node);
23205 * Clean up MS wordisms...
23207 cleanWord : function(node)
23210 this.cleanWord(this.doc.body);
23215 node.nodeName == 'SPAN' &&
23216 !node.hasAttributes() &&
23217 node.childNodes.length == 1 &&
23218 node.firstChild.nodeName == "#text"
23220 var textNode = node.firstChild;
23221 node.removeChild(textNode);
23222 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
23223 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
23225 node.parentNode.insertBefore(textNode, node);
23226 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
23227 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
23229 node.parentNode.removeChild(node);
23232 if (node.nodeName == "#text") {
23233 // clean up silly Windows -- stuff?
23236 if (node.nodeName == "#comment") {
23237 node.parentNode.removeChild(node);
23238 // clean up silly Windows -- stuff?
23242 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23243 node.parentNode.removeChild(node);
23246 //Roo.log(node.tagName);
23247 // remove - but keep children..
23248 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
23249 //Roo.log('-- removed');
23250 while (node.childNodes.length) {
23251 var cn = node.childNodes[0];
23252 node.removeChild(cn);
23253 node.parentNode.insertBefore(cn, node);
23254 // move node to parent - and clean it..
23255 this.cleanWord(cn);
23257 node.parentNode.removeChild(node);
23258 /// no need to iterate chidlren = it's got none..
23259 //this.iterateChildren(node, this.cleanWord);
23263 if (node.className.length) {
23265 var cn = node.className.split(/\W+/);
23267 Roo.each(cn, function(cls) {
23268 if (cls.match(/Mso[a-zA-Z]+/)) {
23273 node.className = cna.length ? cna.join(' ') : '';
23275 node.removeAttribute("class");
23279 if (node.hasAttribute("lang")) {
23280 node.removeAttribute("lang");
23283 if (node.hasAttribute("style")) {
23285 var styles = node.getAttribute("style").split(";");
23287 Roo.each(styles, function(s) {
23288 if (!s.match(/:/)) {
23291 var kv = s.split(":");
23292 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23295 // what ever is left... we allow.
23298 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23299 if (!nstyle.length) {
23300 node.removeAttribute('style');
23303 this.iterateChildren(node, this.cleanWord);
23309 * iterateChildren of a Node, calling fn each time, using this as the scole..
23310 * @param {DomNode} node node to iterate children of.
23311 * @param {Function} fn method of this class to call on each item.
23313 iterateChildren : function(node, fn)
23315 if (!node.childNodes.length) {
23318 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23319 fn.call(this, node.childNodes[i])
23325 * cleanTableWidths.
23327 * Quite often pasting from word etc.. results in tables with column and widths.
23328 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23331 cleanTableWidths : function(node)
23336 this.cleanTableWidths(this.doc.body);
23341 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23344 Roo.log(node.tagName);
23345 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23346 this.iterateChildren(node, this.cleanTableWidths);
23349 if (node.hasAttribute('width')) {
23350 node.removeAttribute('width');
23354 if (node.hasAttribute("style")) {
23357 var styles = node.getAttribute("style").split(";");
23359 Roo.each(styles, function(s) {
23360 if (!s.match(/:/)) {
23363 var kv = s.split(":");
23364 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23367 // what ever is left... we allow.
23370 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23371 if (!nstyle.length) {
23372 node.removeAttribute('style');
23376 this.iterateChildren(node, this.cleanTableWidths);
23384 domToHTML : function(currentElement, depth, nopadtext) {
23386 depth = depth || 0;
23387 nopadtext = nopadtext || false;
23389 if (!currentElement) {
23390 return this.domToHTML(this.doc.body);
23393 //Roo.log(currentElement);
23395 var allText = false;
23396 var nodeName = currentElement.nodeName;
23397 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23399 if (nodeName == '#text') {
23401 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23406 if (nodeName != 'BODY') {
23409 // Prints the node tagName, such as <A>, <IMG>, etc
23412 for(i = 0; i < currentElement.attributes.length;i++) {
23414 var aname = currentElement.attributes.item(i).name;
23415 if (!currentElement.attributes.item(i).value.length) {
23418 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23421 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23430 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23433 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23438 // Traverse the tree
23440 var currentElementChild = currentElement.childNodes.item(i);
23441 var allText = true;
23442 var innerHTML = '';
23444 while (currentElementChild) {
23445 // Formatting code (indent the tree so it looks nice on the screen)
23446 var nopad = nopadtext;
23447 if (lastnode == 'SPAN') {
23451 if (currentElementChild.nodeName == '#text') {
23452 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23453 toadd = nopadtext ? toadd : toadd.trim();
23454 if (!nopad && toadd.length > 80) {
23455 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23457 innerHTML += toadd;
23460 currentElementChild = currentElement.childNodes.item(i);
23466 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23468 // Recursively traverse the tree structure of the child node
23469 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23470 lastnode = currentElementChild.nodeName;
23472 currentElementChild=currentElement.childNodes.item(i);
23478 // The remaining code is mostly for formatting the tree
23479 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23484 ret+= "</"+tagName+">";
23490 applyBlacklists : function()
23492 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23493 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23497 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23498 if (b.indexOf(tag) > -1) {
23501 this.white.push(tag);
23505 Roo.each(w, function(tag) {
23506 if (b.indexOf(tag) > -1) {
23509 if (this.white.indexOf(tag) > -1) {
23512 this.white.push(tag);
23517 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23518 if (w.indexOf(tag) > -1) {
23521 this.black.push(tag);
23525 Roo.each(b, function(tag) {
23526 if (w.indexOf(tag) > -1) {
23529 if (this.black.indexOf(tag) > -1) {
23532 this.black.push(tag);
23537 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23538 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23542 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23543 if (b.indexOf(tag) > -1) {
23546 this.cwhite.push(tag);
23550 Roo.each(w, function(tag) {
23551 if (b.indexOf(tag) > -1) {
23554 if (this.cwhite.indexOf(tag) > -1) {
23557 this.cwhite.push(tag);
23562 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23563 if (w.indexOf(tag) > -1) {
23566 this.cblack.push(tag);
23570 Roo.each(b, function(tag) {
23571 if (w.indexOf(tag) > -1) {
23574 if (this.cblack.indexOf(tag) > -1) {
23577 this.cblack.push(tag);
23582 setStylesheets : function(stylesheets)
23584 if(typeof(stylesheets) == 'string'){
23585 Roo.get(this.iframe.contentDocument.head).createChild({
23587 rel : 'stylesheet',
23596 Roo.each(stylesheets, function(s) {
23601 Roo.get(_this.iframe.contentDocument.head).createChild({
23603 rel : 'stylesheet',
23612 removeStylesheets : function()
23616 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23621 setStyle : function(style)
23623 Roo.get(this.iframe.contentDocument.head).createChild({
23632 // hide stuff that is not compatible
23646 * @event specialkey
23650 * @cfg {String} fieldClass @hide
23653 * @cfg {String} focusClass @hide
23656 * @cfg {String} autoCreate @hide
23659 * @cfg {String} inputType @hide
23662 * @cfg {String} invalidClass @hide
23665 * @cfg {String} invalidText @hide
23668 * @cfg {String} msgFx @hide
23671 * @cfg {String} validateOnBlur @hide
23675 Roo.HtmlEditorCore.white = [
23676 'area', 'br', 'img', 'input', 'hr', 'wbr',
23678 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23679 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23680 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23681 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23682 'table', 'ul', 'xmp',
23684 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23687 'dir', 'menu', 'ol', 'ul', 'dl',
23693 Roo.HtmlEditorCore.black = [
23694 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23696 'base', 'basefont', 'bgsound', 'blink', 'body',
23697 'frame', 'frameset', 'head', 'html', 'ilayer',
23698 'iframe', 'layer', 'link', 'meta', 'object',
23699 'script', 'style' ,'title', 'xml' // clean later..
23701 Roo.HtmlEditorCore.clean = [
23702 'script', 'style', 'title', 'xml'
23704 Roo.HtmlEditorCore.remove = [
23709 Roo.HtmlEditorCore.ablack = [
23713 Roo.HtmlEditorCore.aclean = [
23714 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23718 Roo.HtmlEditorCore.pwhite= [
23719 'http', 'https', 'mailto'
23722 // white listed style attributes.
23723 Roo.HtmlEditorCore.cwhite= [
23724 // 'text-align', /// default is to allow most things..
23730 // black listed style attributes.
23731 Roo.HtmlEditorCore.cblack= [
23732 // 'font-size' -- this can be set by the project
23736 Roo.HtmlEditorCore.swapCodes =[
23755 * @class Roo.bootstrap.HtmlEditor
23756 * @extends Roo.bootstrap.TextArea
23757 * Bootstrap HtmlEditor class
23760 * Create a new HtmlEditor
23761 * @param {Object} config The config object
23764 Roo.bootstrap.HtmlEditor = function(config){
23765 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23766 if (!this.toolbars) {
23767 this.toolbars = [];
23770 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23773 * @event initialize
23774 * Fires when the editor is fully initialized (including the iframe)
23775 * @param {HtmlEditor} this
23780 * Fires when the editor is first receives the focus. Any insertion must wait
23781 * until after this event.
23782 * @param {HtmlEditor} this
23786 * @event beforesync
23787 * Fires before the textarea is updated with content from the editor iframe. Return false
23788 * to cancel the sync.
23789 * @param {HtmlEditor} this
23790 * @param {String} html
23794 * @event beforepush
23795 * Fires before the iframe editor is updated with content from the textarea. Return false
23796 * to cancel the push.
23797 * @param {HtmlEditor} this
23798 * @param {String} html
23803 * Fires when the textarea is updated with content from the editor iframe.
23804 * @param {HtmlEditor} this
23805 * @param {String} html
23810 * Fires when the iframe editor is updated with content from the textarea.
23811 * @param {HtmlEditor} this
23812 * @param {String} html
23816 * @event editmodechange
23817 * Fires when the editor switches edit modes
23818 * @param {HtmlEditor} this
23819 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23821 editmodechange: true,
23823 * @event editorevent
23824 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23825 * @param {HtmlEditor} this
23829 * @event firstfocus
23830 * Fires when on first focus - needed by toolbars..
23831 * @param {HtmlEditor} this
23836 * Auto save the htmlEditor value as a file into Events
23837 * @param {HtmlEditor} this
23841 * @event savedpreview
23842 * preview the saved version of htmlEditor
23843 * @param {HtmlEditor} this
23850 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23854 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23859 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23864 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23869 * @cfg {Number} height (in pixels)
23873 * @cfg {Number} width (in pixels)
23878 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23881 stylesheets: false,
23886 // private properties
23887 validationEvent : false,
23889 initialized : false,
23892 onFocus : Roo.emptyFn,
23894 hideMode:'offsets',
23896 tbContainer : false,
23900 toolbarContainer :function() {
23901 return this.wrap.select('.x-html-editor-tb',true).first();
23905 * Protected method that will not generally be called directly. It
23906 * is called when the editor creates its toolbar. Override this method if you need to
23907 * add custom toolbar buttons.
23908 * @param {HtmlEditor} editor
23910 createToolbar : function(){
23911 Roo.log('renewing');
23912 Roo.log("create toolbars");
23914 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23915 this.toolbars[0].render(this.toolbarContainer());
23919 // if (!editor.toolbars || !editor.toolbars.length) {
23920 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23923 // for (var i =0 ; i < editor.toolbars.length;i++) {
23924 // editor.toolbars[i] = Roo.factory(
23925 // typeof(editor.toolbars[i]) == 'string' ?
23926 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23927 // Roo.bootstrap.HtmlEditor);
23928 // editor.toolbars[i].init(editor);
23934 onRender : function(ct, position)
23936 // Roo.log("Call onRender: " + this.xtype);
23938 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23940 this.wrap = this.inputEl().wrap({
23941 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23944 this.editorcore.onRender(ct, position);
23946 if (this.resizable) {
23947 this.resizeEl = new Roo.Resizable(this.wrap, {
23951 minHeight : this.height,
23952 height: this.height,
23953 handles : this.resizable,
23956 resize : function(r, w, h) {
23957 _t.onResize(w,h); // -something
23963 this.createToolbar(this);
23966 if(!this.width && this.resizable){
23967 this.setSize(this.wrap.getSize());
23969 if (this.resizeEl) {
23970 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23971 // should trigger onReize..
23977 onResize : function(w, h)
23979 Roo.log('resize: ' +w + ',' + h );
23980 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23984 if(this.inputEl() ){
23985 if(typeof w == 'number'){
23986 var aw = w - this.wrap.getFrameWidth('lr');
23987 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23990 if(typeof h == 'number'){
23991 var tbh = -11; // fixme it needs to tool bar size!
23992 for (var i =0; i < this.toolbars.length;i++) {
23993 // fixme - ask toolbars for heights?
23994 tbh += this.toolbars[i].el.getHeight();
23995 //if (this.toolbars[i].footer) {
23996 // tbh += this.toolbars[i].footer.el.getHeight();
24004 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24005 ah -= 5; // knock a few pixes off for look..
24006 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
24010 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
24011 this.editorcore.onResize(ew,eh);
24016 * Toggles the editor between standard and source edit mode.
24017 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24019 toggleSourceEdit : function(sourceEditMode)
24021 this.editorcore.toggleSourceEdit(sourceEditMode);
24023 if(this.editorcore.sourceEditMode){
24024 Roo.log('editor - showing textarea');
24027 // Roo.log(this.syncValue());
24029 this.inputEl().removeClass(['hide', 'x-hidden']);
24030 this.inputEl().dom.removeAttribute('tabIndex');
24031 this.inputEl().focus();
24033 Roo.log('editor - hiding textarea');
24035 // Roo.log(this.pushValue());
24038 this.inputEl().addClass(['hide', 'x-hidden']);
24039 this.inputEl().dom.setAttribute('tabIndex', -1);
24040 //this.deferFocus();
24043 if(this.resizable){
24044 this.setSize(this.wrap.getSize());
24047 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
24050 // private (for BoxComponent)
24051 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24053 // private (for BoxComponent)
24054 getResizeEl : function(){
24058 // private (for BoxComponent)
24059 getPositionEl : function(){
24064 initEvents : function(){
24065 this.originalValue = this.getValue();
24069 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24072 // markInvalid : Roo.emptyFn,
24074 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24077 // clearInvalid : Roo.emptyFn,
24079 setValue : function(v){
24080 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24081 this.editorcore.pushValue();
24086 deferFocus : function(){
24087 this.focus.defer(10, this);
24091 focus : function(){
24092 this.editorcore.focus();
24098 onDestroy : function(){
24104 for (var i =0; i < this.toolbars.length;i++) {
24105 // fixme - ask toolbars for heights?
24106 this.toolbars[i].onDestroy();
24109 this.wrap.dom.innerHTML = '';
24110 this.wrap.remove();
24115 onFirstFocus : function(){
24116 //Roo.log("onFirstFocus");
24117 this.editorcore.onFirstFocus();
24118 for (var i =0; i < this.toolbars.length;i++) {
24119 this.toolbars[i].onFirstFocus();
24125 syncValue : function()
24127 this.editorcore.syncValue();
24130 pushValue : function()
24132 this.editorcore.pushValue();
24136 // hide stuff that is not compatible
24150 * @event specialkey
24154 * @cfg {String} fieldClass @hide
24157 * @cfg {String} focusClass @hide
24160 * @cfg {String} autoCreate @hide
24163 * @cfg {String} inputType @hide
24167 * @cfg {String} invalidText @hide
24170 * @cfg {String} msgFx @hide
24173 * @cfg {String} validateOnBlur @hide
24182 Roo.namespace('Roo.bootstrap.htmleditor');
24184 * @class Roo.bootstrap.HtmlEditorToolbar1
24190 new Roo.bootstrap.HtmlEditor({
24193 new Roo.bootstrap.HtmlEditorToolbar1({
24194 disable : { fonts: 1 , format: 1, ..., ... , ...],
24200 * @cfg {Object} disable List of elements to disable..
24201 * @cfg {Array} btns List of additional buttons.
24205 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24208 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24211 Roo.apply(this, config);
24213 // default disabled, based on 'good practice'..
24214 this.disable = this.disable || {};
24215 Roo.applyIf(this.disable, {
24218 specialElements : true
24220 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24222 this.editor = config.editor;
24223 this.editorcore = config.editor.editorcore;
24225 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24227 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24228 // dont call parent... till later.
24230 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24235 editorcore : false,
24240 "h1","h2","h3","h4","h5","h6",
24242 "abbr", "acronym", "address", "cite", "samp", "var",
24246 onRender : function(ct, position)
24248 // Roo.log("Call onRender: " + this.xtype);
24250 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24252 this.el.dom.style.marginBottom = '0';
24254 var editorcore = this.editorcore;
24255 var editor= this.editor;
24258 var btn = function(id,cmd , toggle, handler, html){
24260 var event = toggle ? 'toggle' : 'click';
24265 xns: Roo.bootstrap,
24269 enableToggle:toggle !== false,
24271 pressed : toggle ? false : null,
24274 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24275 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24281 // var cb_box = function...
24286 xns: Roo.bootstrap,
24291 xns: Roo.bootstrap,
24295 Roo.each(this.formats, function(f) {
24296 style.menu.items.push({
24298 xns: Roo.bootstrap,
24299 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24304 editorcore.insertTag(this.tagname);
24311 children.push(style);
24313 btn('bold',false,true);
24314 btn('italic',false,true);
24315 btn('align-left', 'justifyleft',true);
24316 btn('align-center', 'justifycenter',true);
24317 btn('align-right' , 'justifyright',true);
24318 btn('link', false, false, function(btn) {
24319 //Roo.log("create link?");
24320 var url = prompt(this.createLinkText, this.defaultLinkValue);
24321 if(url && url != 'http:/'+'/'){
24322 this.editorcore.relayCmd('createlink', url);
24325 btn('list','insertunorderedlist',true);
24326 btn('pencil', false,true, function(btn){
24328 this.toggleSourceEdit(btn.pressed);
24331 if (this.editor.btns.length > 0) {
24332 for (var i = 0; i<this.editor.btns.length; i++) {
24333 children.push(this.editor.btns[i]);
24341 xns: Roo.bootstrap,
24346 xns: Roo.bootstrap,
24351 cog.menu.items.push({
24353 xns: Roo.bootstrap,
24354 html : Clean styles,
24359 editorcore.insertTag(this.tagname);
24368 this.xtype = 'NavSimplebar';
24370 for(var i=0;i< children.length;i++) {
24372 this.buttons.add(this.addxtypeChild(children[i]));
24376 editor.on('editorevent', this.updateToolbar, this);
24378 onBtnClick : function(id)
24380 this.editorcore.relayCmd(id);
24381 this.editorcore.focus();
24385 * Protected method that will not generally be called directly. It triggers
24386 * a toolbar update by reading the markup state of the current selection in the editor.
24388 updateToolbar: function(){
24390 if(!this.editorcore.activated){
24391 this.editor.onFirstFocus(); // is this neeed?
24395 var btns = this.buttons;
24396 var doc = this.editorcore.doc;
24397 btns.get('bold').setActive(doc.queryCommandState('bold'));
24398 btns.get('italic').setActive(doc.queryCommandState('italic'));
24399 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24401 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24402 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24403 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24405 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24406 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24409 var ans = this.editorcore.getAllAncestors();
24410 if (this.formatCombo) {
24413 var store = this.formatCombo.store;
24414 this.formatCombo.setValue("");
24415 for (var i =0; i < ans.length;i++) {
24416 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24418 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24426 // hides menus... - so this cant be on a menu...
24427 Roo.bootstrap.MenuMgr.hideAll();
24429 Roo.bootstrap.MenuMgr.hideAll();
24430 //this.editorsyncValue();
24432 onFirstFocus: function() {
24433 this.buttons.each(function(item){
24437 toggleSourceEdit : function(sourceEditMode){
24440 if(sourceEditMode){
24441 Roo.log("disabling buttons");
24442 this.buttons.each( function(item){
24443 if(item.cmd != 'pencil'){
24449 Roo.log("enabling buttons");
24450 if(this.editorcore.initialized){
24451 this.buttons.each( function(item){
24457 Roo.log("calling toggole on editor");
24458 // tell the editor that it's been pressed..
24459 this.editor.toggleSourceEdit(sourceEditMode);
24469 * @class Roo.bootstrap.Table.AbstractSelectionModel
24470 * @extends Roo.util.Observable
24471 * Abstract base class for grid SelectionModels. It provides the interface that should be
24472 * implemented by descendant classes. This class should not be directly instantiated.
24475 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24476 this.locked = false;
24477 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24481 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24482 /** @ignore Called by the grid automatically. Do not call directly. */
24483 init : function(grid){
24489 * Locks the selections.
24492 this.locked = true;
24496 * Unlocks the selections.
24498 unlock : function(){
24499 this.locked = false;
24503 * Returns true if the selections are locked.
24504 * @return {Boolean}
24506 isLocked : function(){
24507 return this.locked;
24511 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24512 * @class Roo.bootstrap.Table.RowSelectionModel
24513 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24514 * It supports multiple selections and keyboard selection/navigation.
24516 * @param {Object} config
24519 Roo.bootstrap.Table.RowSelectionModel = function(config){
24520 Roo.apply(this, config);
24521 this.selections = new Roo.util.MixedCollection(false, function(o){
24526 this.lastActive = false;
24530 * @event selectionchange
24531 * Fires when the selection changes
24532 * @param {SelectionModel} this
24534 "selectionchange" : true,
24536 * @event afterselectionchange
24537 * Fires after the selection changes (eg. by key press or clicking)
24538 * @param {SelectionModel} this
24540 "afterselectionchange" : true,
24542 * @event beforerowselect
24543 * Fires when a row is selected being selected, return false to cancel.
24544 * @param {SelectionModel} this
24545 * @param {Number} rowIndex The selected index
24546 * @param {Boolean} keepExisting False if other selections will be cleared
24548 "beforerowselect" : true,
24551 * Fires when a row is selected.
24552 * @param {SelectionModel} this
24553 * @param {Number} rowIndex The selected index
24554 * @param {Roo.data.Record} r The record
24556 "rowselect" : true,
24558 * @event rowdeselect
24559 * Fires when a row is deselected.
24560 * @param {SelectionModel} this
24561 * @param {Number} rowIndex The selected index
24563 "rowdeselect" : true
24565 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24566 this.locked = false;
24569 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24571 * @cfg {Boolean} singleSelect
24572 * True to allow selection of only one row at a time (defaults to false)
24574 singleSelect : false,
24577 initEvents : function()
24580 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24581 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24582 //}else{ // allow click to work like normal
24583 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24585 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24586 this.grid.on("rowclick", this.handleMouseDown, this);
24588 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24589 "up" : function(e){
24591 this.selectPrevious(e.shiftKey);
24592 }else if(this.last !== false && this.lastActive !== false){
24593 var last = this.last;
24594 this.selectRange(this.last, this.lastActive-1);
24595 this.grid.getView().focusRow(this.lastActive);
24596 if(last !== false){
24600 this.selectFirstRow();
24602 this.fireEvent("afterselectionchange", this);
24604 "down" : function(e){
24606 this.selectNext(e.shiftKey);
24607 }else if(this.last !== false && this.lastActive !== false){
24608 var last = this.last;
24609 this.selectRange(this.last, this.lastActive+1);
24610 this.grid.getView().focusRow(this.lastActive);
24611 if(last !== false){
24615 this.selectFirstRow();
24617 this.fireEvent("afterselectionchange", this);
24621 this.grid.store.on('load', function(){
24622 this.selections.clear();
24625 var view = this.grid.view;
24626 view.on("refresh", this.onRefresh, this);
24627 view.on("rowupdated", this.onRowUpdated, this);
24628 view.on("rowremoved", this.onRemove, this);
24633 onRefresh : function()
24635 var ds = this.grid.store, i, v = this.grid.view;
24636 var s = this.selections;
24637 s.each(function(r){
24638 if((i = ds.indexOfId(r.id)) != -1){
24647 onRemove : function(v, index, r){
24648 this.selections.remove(r);
24652 onRowUpdated : function(v, index, r){
24653 if(this.isSelected(r)){
24654 v.onRowSelect(index);
24660 * @param {Array} records The records to select
24661 * @param {Boolean} keepExisting (optional) True to keep existing selections
24663 selectRecords : function(records, keepExisting)
24666 this.clearSelections();
24668 var ds = this.grid.store;
24669 for(var i = 0, len = records.length; i < len; i++){
24670 this.selectRow(ds.indexOf(records[i]), true);
24675 * Gets the number of selected rows.
24678 getCount : function(){
24679 return this.selections.length;
24683 * Selects the first row in the grid.
24685 selectFirstRow : function(){
24690 * Select the last row.
24691 * @param {Boolean} keepExisting (optional) True to keep existing selections
24693 selectLastRow : function(keepExisting){
24694 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24695 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24699 * Selects the row immediately following the last selected row.
24700 * @param {Boolean} keepExisting (optional) True to keep existing selections
24702 selectNext : function(keepExisting)
24704 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24705 this.selectRow(this.last+1, keepExisting);
24706 this.grid.getView().focusRow(this.last);
24711 * Selects the row that precedes the last selected row.
24712 * @param {Boolean} keepExisting (optional) True to keep existing selections
24714 selectPrevious : function(keepExisting){
24716 this.selectRow(this.last-1, keepExisting);
24717 this.grid.getView().focusRow(this.last);
24722 * Returns the selected records
24723 * @return {Array} Array of selected records
24725 getSelections : function(){
24726 return [].concat(this.selections.items);
24730 * Returns the first selected record.
24733 getSelected : function(){
24734 return this.selections.itemAt(0);
24739 * Clears all selections.
24741 clearSelections : function(fast)
24747 var ds = this.grid.store;
24748 var s = this.selections;
24749 s.each(function(r){
24750 this.deselectRow(ds.indexOfId(r.id));
24754 this.selections.clear();
24761 * Selects all rows.
24763 selectAll : function(){
24767 this.selections.clear();
24768 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24769 this.selectRow(i, true);
24774 * Returns True if there is a selection.
24775 * @return {Boolean}
24777 hasSelection : function(){
24778 return this.selections.length > 0;
24782 * Returns True if the specified row is selected.
24783 * @param {Number/Record} record The record or index of the record to check
24784 * @return {Boolean}
24786 isSelected : function(index){
24787 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24788 return (r && this.selections.key(r.id) ? true : false);
24792 * Returns True if the specified record id is selected.
24793 * @param {String} id The id of record to check
24794 * @return {Boolean}
24796 isIdSelected : function(id){
24797 return (this.selections.key(id) ? true : false);
24802 handleMouseDBClick : function(e, t){
24806 handleMouseDown : function(e, t)
24808 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24809 if(this.isLocked() || rowIndex < 0 ){
24812 if(e.shiftKey && this.last !== false){
24813 var last = this.last;
24814 this.selectRange(last, rowIndex, e.ctrlKey);
24815 this.last = last; // reset the last
24819 var isSelected = this.isSelected(rowIndex);
24820 //Roo.log("select row:" + rowIndex);
24822 this.deselectRow(rowIndex);
24824 this.selectRow(rowIndex, true);
24828 if(e.button !== 0 && isSelected){
24829 alert('rowIndex 2: ' + rowIndex);
24830 view.focusRow(rowIndex);
24831 }else if(e.ctrlKey && isSelected){
24832 this.deselectRow(rowIndex);
24833 }else if(!isSelected){
24834 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24835 view.focusRow(rowIndex);
24839 this.fireEvent("afterselectionchange", this);
24842 handleDragableRowClick : function(grid, rowIndex, e)
24844 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24845 this.selectRow(rowIndex, false);
24846 grid.view.focusRow(rowIndex);
24847 this.fireEvent("afterselectionchange", this);
24852 * Selects multiple rows.
24853 * @param {Array} rows Array of the indexes of the row to select
24854 * @param {Boolean} keepExisting (optional) True to keep existing selections
24856 selectRows : function(rows, keepExisting){
24858 this.clearSelections();
24860 for(var i = 0, len = rows.length; i < len; i++){
24861 this.selectRow(rows[i], true);
24866 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24867 * @param {Number} startRow The index of the first row in the range
24868 * @param {Number} endRow The index of the last row in the range
24869 * @param {Boolean} keepExisting (optional) True to retain existing selections
24871 selectRange : function(startRow, endRow, keepExisting){
24876 this.clearSelections();
24878 if(startRow <= endRow){
24879 for(var i = startRow; i <= endRow; i++){
24880 this.selectRow(i, true);
24883 for(var i = startRow; i >= endRow; i--){
24884 this.selectRow(i, true);
24890 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24891 * @param {Number} startRow The index of the first row in the range
24892 * @param {Number} endRow The index of the last row in the range
24894 deselectRange : function(startRow, endRow, preventViewNotify){
24898 for(var i = startRow; i <= endRow; i++){
24899 this.deselectRow(i, preventViewNotify);
24905 * @param {Number} row The index of the row to select
24906 * @param {Boolean} keepExisting (optional) True to keep existing selections
24908 selectRow : function(index, keepExisting, preventViewNotify)
24910 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24913 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24914 if(!keepExisting || this.singleSelect){
24915 this.clearSelections();
24918 var r = this.grid.store.getAt(index);
24919 //console.log('selectRow - record id :' + r.id);
24921 this.selections.add(r);
24922 this.last = this.lastActive = index;
24923 if(!preventViewNotify){
24924 var proxy = new Roo.Element(
24925 this.grid.getRowDom(index)
24927 proxy.addClass('bg-info info');
24929 this.fireEvent("rowselect", this, index, r);
24930 this.fireEvent("selectionchange", this);
24936 * @param {Number} row The index of the row to deselect
24938 deselectRow : function(index, preventViewNotify)
24943 if(this.last == index){
24946 if(this.lastActive == index){
24947 this.lastActive = false;
24950 var r = this.grid.store.getAt(index);
24955 this.selections.remove(r);
24956 //.console.log('deselectRow - record id :' + r.id);
24957 if(!preventViewNotify){
24959 var proxy = new Roo.Element(
24960 this.grid.getRowDom(index)
24962 proxy.removeClass('bg-info info');
24964 this.fireEvent("rowdeselect", this, index);
24965 this.fireEvent("selectionchange", this);
24969 restoreLast : function(){
24971 this.last = this._last;
24976 acceptsNav : function(row, col, cm){
24977 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24981 onEditorKey : function(field, e){
24982 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24987 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24989 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24991 }else if(k == e.ENTER && !e.ctrlKey){
24995 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24997 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24999 }else if(k == e.ESC){
25003 g.startEditing(newCell[0], newCell[1]);
25009 * Ext JS Library 1.1.1
25010 * Copyright(c) 2006-2007, Ext JS, LLC.
25012 * Originally Released Under LGPL - original licence link has changed is not relivant.
25015 * <script type="text/javascript">
25019 * @class Roo.bootstrap.PagingToolbar
25020 * @extends Roo.bootstrap.NavSimplebar
25021 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
25023 * Create a new PagingToolbar
25024 * @param {Object} config The config object
25025 * @param {Roo.data.Store} store
25027 Roo.bootstrap.PagingToolbar = function(config)
25029 // old args format still supported... - xtype is prefered..
25030 // created from xtype...
25032 this.ds = config.dataSource;
25034 if (config.store && !this.ds) {
25035 this.store= Roo.factory(config.store, Roo.data);
25036 this.ds = this.store;
25037 this.ds.xmodule = this.xmodule || false;
25040 this.toolbarItems = [];
25041 if (config.items) {
25042 this.toolbarItems = config.items;
25045 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
25050 this.bind(this.ds);
25053 if (Roo.bootstrap.version == 4) {
25054 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
25056 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
25061 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
25063 * @cfg {Roo.data.Store} dataSource
25064 * The underlying data store providing the paged data
25067 * @cfg {String/HTMLElement/Element} container
25068 * container The id or element that will contain the toolbar
25071 * @cfg {Boolean} displayInfo
25072 * True to display the displayMsg (defaults to false)
25075 * @cfg {Number} pageSize
25076 * The number of records to display per page (defaults to 20)
25080 * @cfg {String} displayMsg
25081 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25083 displayMsg : 'Displaying {0} - {1} of {2}',
25085 * @cfg {String} emptyMsg
25086 * The message to display when no records are found (defaults to "No data to display")
25088 emptyMsg : 'No data to display',
25090 * Customizable piece of the default paging text (defaults to "Page")
25093 beforePageText : "Page",
25095 * Customizable piece of the default paging text (defaults to "of %0")
25098 afterPageText : "of {0}",
25100 * Customizable piece of the default paging text (defaults to "First Page")
25103 firstText : "First Page",
25105 * Customizable piece of the default paging text (defaults to "Previous Page")
25108 prevText : "Previous Page",
25110 * Customizable piece of the default paging text (defaults to "Next Page")
25113 nextText : "Next Page",
25115 * Customizable piece of the default paging text (defaults to "Last Page")
25118 lastText : "Last Page",
25120 * Customizable piece of the default paging text (defaults to "Refresh")
25123 refreshText : "Refresh",
25127 onRender : function(ct, position)
25129 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25130 this.navgroup.parentId = this.id;
25131 this.navgroup.onRender(this.el, null);
25132 // add the buttons to the navgroup
25134 if(this.displayInfo){
25135 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25136 this.displayEl = this.el.select('.x-paging-info', true).first();
25137 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25138 // this.displayEl = navel.el.select('span',true).first();
25144 Roo.each(_this.buttons, function(e){ // this might need to use render????
25145 Roo.factory(e).render(_this.el);
25149 Roo.each(_this.toolbarItems, function(e) {
25150 _this.navgroup.addItem(e);
25154 this.first = this.navgroup.addItem({
25155 tooltip: this.firstText,
25156 cls: "prev btn-outline-secondary",
25157 html : ' <i class="fa fa-step-backward"></i>',
25159 preventDefault: true,
25160 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25163 this.prev = this.navgroup.addItem({
25164 tooltip: this.prevText,
25165 cls: "prev btn-outline-secondary",
25166 html : ' <i class="fa fa-backward"></i>',
25168 preventDefault: true,
25169 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25171 //this.addSeparator();
25174 var field = this.navgroup.addItem( {
25176 cls : 'x-paging-position btn-outline-secondary',
25178 html : this.beforePageText +
25179 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25180 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25183 this.field = field.el.select('input', true).first();
25184 this.field.on("keydown", this.onPagingKeydown, this);
25185 this.field.on("focus", function(){this.dom.select();});
25188 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25189 //this.field.setHeight(18);
25190 //this.addSeparator();
25191 this.next = this.navgroup.addItem({
25192 tooltip: this.nextText,
25193 cls: "next btn-outline-secondary",
25194 html : ' <i class="fa fa-forward"></i>',
25196 preventDefault: true,
25197 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25199 this.last = this.navgroup.addItem({
25200 tooltip: this.lastText,
25201 html : ' <i class="fa fa-step-forward"></i>',
25202 cls: "next btn-outline-secondary",
25204 preventDefault: true,
25205 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25207 //this.addSeparator();
25208 this.loading = this.navgroup.addItem({
25209 tooltip: this.refreshText,
25210 cls: "btn-outline-secondary",
25211 html : ' <i class="fa fa-refresh"></i>',
25212 preventDefault: true,
25213 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25219 updateInfo : function(){
25220 if(this.displayEl){
25221 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25222 var msg = count == 0 ?
25226 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25228 this.displayEl.update(msg);
25233 onLoad : function(ds, r, o)
25235 this.cursor = o.params.start ? o.params.start : 0;
25237 var d = this.getPageData(),
25242 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25243 this.field.dom.value = ap;
25244 this.first.setDisabled(ap == 1);
25245 this.prev.setDisabled(ap == 1);
25246 this.next.setDisabled(ap == ps);
25247 this.last.setDisabled(ap == ps);
25248 this.loading.enable();
25253 getPageData : function(){
25254 var total = this.ds.getTotalCount();
25257 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25258 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25263 onLoadError : function(){
25264 this.loading.enable();
25268 onPagingKeydown : function(e){
25269 var k = e.getKey();
25270 var d = this.getPageData();
25272 var v = this.field.dom.value, pageNum;
25273 if(!v || isNaN(pageNum = parseInt(v, 10))){
25274 this.field.dom.value = d.activePage;
25277 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25278 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25281 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))
25283 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25284 this.field.dom.value = pageNum;
25285 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25288 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25290 var v = this.field.dom.value, pageNum;
25291 var increment = (e.shiftKey) ? 10 : 1;
25292 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25295 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25296 this.field.dom.value = d.activePage;
25299 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25301 this.field.dom.value = parseInt(v, 10) + increment;
25302 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25303 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25310 beforeLoad : function(){
25312 this.loading.disable();
25317 onClick : function(which){
25326 ds.load({params:{start: 0, limit: this.pageSize}});
25329 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25332 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25335 var total = ds.getTotalCount();
25336 var extra = total % this.pageSize;
25337 var lastStart = extra ? (total - extra) : total-this.pageSize;
25338 ds.load({params:{start: lastStart, limit: this.pageSize}});
25341 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25347 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25348 * @param {Roo.data.Store} store The data store to unbind
25350 unbind : function(ds){
25351 ds.un("beforeload", this.beforeLoad, this);
25352 ds.un("load", this.onLoad, this);
25353 ds.un("loadexception", this.onLoadError, this);
25354 ds.un("remove", this.updateInfo, this);
25355 ds.un("add", this.updateInfo, this);
25356 this.ds = undefined;
25360 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25361 * @param {Roo.data.Store} store The data store to bind
25363 bind : function(ds){
25364 ds.on("beforeload", this.beforeLoad, this);
25365 ds.on("load", this.onLoad, this);
25366 ds.on("loadexception", this.onLoadError, this);
25367 ds.on("remove", this.updateInfo, this);
25368 ds.on("add", this.updateInfo, this);
25379 * @class Roo.bootstrap.MessageBar
25380 * @extends Roo.bootstrap.Component
25381 * Bootstrap MessageBar class
25382 * @cfg {String} html contents of the MessageBar
25383 * @cfg {String} weight (info | success | warning | danger) default info
25384 * @cfg {String} beforeClass insert the bar before the given class
25385 * @cfg {Boolean} closable (true | false) default false
25386 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25389 * Create a new Element
25390 * @param {Object} config The config object
25393 Roo.bootstrap.MessageBar = function(config){
25394 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25397 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25403 beforeClass: 'bootstrap-sticky-wrap',
25405 getAutoCreate : function(){
25409 cls: 'alert alert-dismissable alert-' + this.weight,
25414 html: this.html || ''
25420 cfg.cls += ' alert-messages-fixed';
25434 onRender : function(ct, position)
25436 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25439 var cfg = Roo.apply({}, this.getAutoCreate());
25443 cfg.cls += ' ' + this.cls;
25446 cfg.style = this.style;
25448 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25450 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25453 this.el.select('>button.close').on('click', this.hide, this);
25459 if (!this.rendered) {
25465 this.fireEvent('show', this);
25471 if (!this.rendered) {
25477 this.fireEvent('hide', this);
25480 update : function()
25482 // var e = this.el.dom.firstChild;
25484 // if(this.closable){
25485 // e = e.nextSibling;
25488 // e.data = this.html || '';
25490 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25506 * @class Roo.bootstrap.Graph
25507 * @extends Roo.bootstrap.Component
25508 * Bootstrap Graph class
25512 @cfg {String} graphtype bar | vbar | pie
25513 @cfg {number} g_x coodinator | centre x (pie)
25514 @cfg {number} g_y coodinator | centre y (pie)
25515 @cfg {number} g_r radius (pie)
25516 @cfg {number} g_height height of the chart (respected by all elements in the set)
25517 @cfg {number} g_width width of the chart (respected by all elements in the set)
25518 @cfg {Object} title The title of the chart
25521 -opts (object) options for the chart
25523 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25524 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25526 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.
25527 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25529 o stretch (boolean)
25531 -opts (object) options for the pie
25534 o startAngle (number)
25535 o endAngle (number)
25539 * Create a new Input
25540 * @param {Object} config The config object
25543 Roo.bootstrap.Graph = function(config){
25544 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25550 * The img click event for the img.
25551 * @param {Roo.EventObject} e
25557 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25568 //g_colors: this.colors,
25575 getAutoCreate : function(){
25586 onRender : function(ct,position){
25589 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25591 if (typeof(Raphael) == 'undefined') {
25592 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25596 this.raphael = Raphael(this.el.dom);
25598 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25599 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25600 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25601 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25603 r.text(160, 10, "Single Series Chart").attr(txtattr);
25604 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25605 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25606 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25608 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25609 r.barchart(330, 10, 300, 220, data1);
25610 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25611 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25614 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25615 // r.barchart(30, 30, 560, 250, xdata, {
25616 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25617 // axis : "0 0 1 1",
25618 // axisxlabels : xdata
25619 // //yvalues : cols,
25622 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25624 // this.load(null,xdata,{
25625 // axis : "0 0 1 1",
25626 // axisxlabels : xdata
25631 load : function(graphtype,xdata,opts)
25633 this.raphael.clear();
25635 graphtype = this.graphtype;
25640 var r = this.raphael,
25641 fin = function () {
25642 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25644 fout = function () {
25645 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25647 pfin = function() {
25648 this.sector.stop();
25649 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25652 this.label[0].stop();
25653 this.label[0].attr({ r: 7.5 });
25654 this.label[1].attr({ "font-weight": 800 });
25657 pfout = function() {
25658 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25661 this.label[0].animate({ r: 5 }, 500, "bounce");
25662 this.label[1].attr({ "font-weight": 400 });
25668 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25671 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25674 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25675 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25677 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25684 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25689 setTitle: function(o)
25694 initEvents: function() {
25697 this.el.on('click', this.onClick, this);
25701 onClick : function(e)
25703 Roo.log('img onclick');
25704 this.fireEvent('click', this, e);
25716 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25719 * @class Roo.bootstrap.dash.NumberBox
25720 * @extends Roo.bootstrap.Component
25721 * Bootstrap NumberBox class
25722 * @cfg {String} headline Box headline
25723 * @cfg {String} content Box content
25724 * @cfg {String} icon Box icon
25725 * @cfg {String} footer Footer text
25726 * @cfg {String} fhref Footer href
25729 * Create a new NumberBox
25730 * @param {Object} config The config object
25734 Roo.bootstrap.dash.NumberBox = function(config){
25735 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25739 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25748 getAutoCreate : function(){
25752 cls : 'small-box ',
25760 cls : 'roo-headline',
25761 html : this.headline
25765 cls : 'roo-content',
25766 html : this.content
25780 cls : 'ion ' + this.icon
25789 cls : 'small-box-footer',
25790 href : this.fhref || '#',
25794 cfg.cn.push(footer);
25801 onRender : function(ct,position){
25802 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25809 setHeadline: function (value)
25811 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25814 setFooter: function (value, href)
25816 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25819 this.el.select('a.small-box-footer',true).first().attr('href', href);
25824 setContent: function (value)
25826 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25829 initEvents: function()
25843 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25846 * @class Roo.bootstrap.dash.TabBox
25847 * @extends Roo.bootstrap.Component
25848 * Bootstrap TabBox class
25849 * @cfg {String} title Title of the TabBox
25850 * @cfg {String} icon Icon of the TabBox
25851 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25852 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25855 * Create a new TabBox
25856 * @param {Object} config The config object
25860 Roo.bootstrap.dash.TabBox = function(config){
25861 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25866 * When a pane is added
25867 * @param {Roo.bootstrap.dash.TabPane} pane
25871 * @event activatepane
25872 * When a pane is activated
25873 * @param {Roo.bootstrap.dash.TabPane} pane
25875 "activatepane" : true
25883 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25888 tabScrollable : false,
25890 getChildContainer : function()
25892 return this.el.select('.tab-content', true).first();
25895 getAutoCreate : function(){
25899 cls: 'pull-left header',
25907 cls: 'fa ' + this.icon
25913 cls: 'nav nav-tabs pull-right',
25919 if(this.tabScrollable){
25926 cls: 'nav nav-tabs pull-right',
25937 cls: 'nav-tabs-custom',
25942 cls: 'tab-content no-padding',
25950 initEvents : function()
25952 //Roo.log('add add pane handler');
25953 this.on('addpane', this.onAddPane, this);
25956 * Updates the box title
25957 * @param {String} html to set the title to.
25959 setTitle : function(value)
25961 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25963 onAddPane : function(pane)
25965 this.panes.push(pane);
25966 //Roo.log('addpane');
25968 // tabs are rendere left to right..
25969 if(!this.showtabs){
25973 var ctr = this.el.select('.nav-tabs', true).first();
25976 var existing = ctr.select('.nav-tab',true);
25977 var qty = existing.getCount();;
25980 var tab = ctr.createChild({
25982 cls : 'nav-tab' + (qty ? '' : ' active'),
25990 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25993 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25995 pane.el.addClass('active');
26000 onTabClick : function(ev,un,ob,pane)
26002 //Roo.log('tab - prev default');
26003 ev.preventDefault();
26006 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
26007 pane.tab.addClass('active');
26008 //Roo.log(pane.title);
26009 this.getChildContainer().select('.tab-pane',true).removeClass('active');
26010 // technically we should have a deactivate event.. but maybe add later.
26011 // and it should not de-activate the selected tab...
26012 this.fireEvent('activatepane', pane);
26013 pane.el.addClass('active');
26014 pane.fireEvent('activate');
26019 getActivePane : function()
26022 Roo.each(this.panes, function(p) {
26023 if(p.el.hasClass('active')){
26044 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26046 * @class Roo.bootstrap.TabPane
26047 * @extends Roo.bootstrap.Component
26048 * Bootstrap TabPane class
26049 * @cfg {Boolean} active (false | true) Default false
26050 * @cfg {String} title title of panel
26054 * Create a new TabPane
26055 * @param {Object} config The config object
26058 Roo.bootstrap.dash.TabPane = function(config){
26059 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26065 * When a pane is activated
26066 * @param {Roo.bootstrap.dash.TabPane} pane
26073 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26078 // the tabBox that this is attached to.
26081 getAutoCreate : function()
26089 cfg.cls += ' active';
26094 initEvents : function()
26096 //Roo.log('trigger add pane handler');
26097 this.parent().fireEvent('addpane', this)
26101 * Updates the tab title
26102 * @param {String} html to set the title to.
26104 setTitle: function(str)
26110 this.tab.select('a', true).first().dom.innerHTML = str;
26127 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26130 * @class Roo.bootstrap.menu.Menu
26131 * @extends Roo.bootstrap.Component
26132 * Bootstrap Menu class - container for Menu
26133 * @cfg {String} html Text of the menu
26134 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26135 * @cfg {String} icon Font awesome icon
26136 * @cfg {String} pos Menu align to (top | bottom) default bottom
26140 * Create a new Menu
26141 * @param {Object} config The config object
26145 Roo.bootstrap.menu.Menu = function(config){
26146 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26150 * @event beforeshow
26151 * Fires before this menu is displayed
26152 * @param {Roo.bootstrap.menu.Menu} this
26156 * @event beforehide
26157 * Fires before this menu is hidden
26158 * @param {Roo.bootstrap.menu.Menu} this
26163 * Fires after this menu is displayed
26164 * @param {Roo.bootstrap.menu.Menu} this
26169 * Fires after this menu is hidden
26170 * @param {Roo.bootstrap.menu.Menu} this
26175 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26176 * @param {Roo.bootstrap.menu.Menu} this
26177 * @param {Roo.EventObject} e
26184 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26188 weight : 'default',
26193 getChildContainer : function() {
26194 if(this.isSubMenu){
26198 return this.el.select('ul.dropdown-menu', true).first();
26201 getAutoCreate : function()
26206 cls : 'roo-menu-text',
26214 cls : 'fa ' + this.icon
26225 cls : 'dropdown-button btn btn-' + this.weight,
26230 cls : 'dropdown-toggle btn btn-' + this.weight,
26240 cls : 'dropdown-menu'
26246 if(this.pos == 'top'){
26247 cfg.cls += ' dropup';
26250 if(this.isSubMenu){
26253 cls : 'dropdown-menu'
26260 onRender : function(ct, position)
26262 this.isSubMenu = ct.hasClass('dropdown-submenu');
26264 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26267 initEvents : function()
26269 if(this.isSubMenu){
26273 this.hidden = true;
26275 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26276 this.triggerEl.on('click', this.onTriggerPress, this);
26278 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26279 this.buttonEl.on('click', this.onClick, this);
26285 if(this.isSubMenu){
26289 return this.el.select('ul.dropdown-menu', true).first();
26292 onClick : function(e)
26294 this.fireEvent("click", this, e);
26297 onTriggerPress : function(e)
26299 if (this.isVisible()) {
26306 isVisible : function(){
26307 return !this.hidden;
26312 this.fireEvent("beforeshow", this);
26314 this.hidden = false;
26315 this.el.addClass('open');
26317 Roo.get(document).on("mouseup", this.onMouseUp, this);
26319 this.fireEvent("show", this);
26326 this.fireEvent("beforehide", this);
26328 this.hidden = true;
26329 this.el.removeClass('open');
26331 Roo.get(document).un("mouseup", this.onMouseUp);
26333 this.fireEvent("hide", this);
26336 onMouseUp : function()
26350 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26353 * @class Roo.bootstrap.menu.Item
26354 * @extends Roo.bootstrap.Component
26355 * Bootstrap MenuItem class
26356 * @cfg {Boolean} submenu (true | false) default false
26357 * @cfg {String} html text of the item
26358 * @cfg {String} href the link
26359 * @cfg {Boolean} disable (true | false) default false
26360 * @cfg {Boolean} preventDefault (true | false) default true
26361 * @cfg {String} icon Font awesome icon
26362 * @cfg {String} pos Submenu align to (left | right) default right
26366 * Create a new Item
26367 * @param {Object} config The config object
26371 Roo.bootstrap.menu.Item = function(config){
26372 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26376 * Fires when the mouse is hovering over this menu
26377 * @param {Roo.bootstrap.menu.Item} this
26378 * @param {Roo.EventObject} e
26383 * Fires when the mouse exits this menu
26384 * @param {Roo.bootstrap.menu.Item} this
26385 * @param {Roo.EventObject} e
26391 * The raw click event for the entire grid.
26392 * @param {Roo.EventObject} e
26398 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26403 preventDefault: true,
26408 getAutoCreate : function()
26413 cls : 'roo-menu-item-text',
26421 cls : 'fa ' + this.icon
26430 href : this.href || '#',
26437 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26441 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26443 if(this.pos == 'left'){
26444 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26451 initEvents : function()
26453 this.el.on('mouseover', this.onMouseOver, this);
26454 this.el.on('mouseout', this.onMouseOut, this);
26456 this.el.select('a', true).first().on('click', this.onClick, this);
26460 onClick : function(e)
26462 if(this.preventDefault){
26463 e.preventDefault();
26466 this.fireEvent("click", this, e);
26469 onMouseOver : function(e)
26471 if(this.submenu && this.pos == 'left'){
26472 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26475 this.fireEvent("mouseover", this, e);
26478 onMouseOut : function(e)
26480 this.fireEvent("mouseout", this, e);
26492 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26495 * @class Roo.bootstrap.menu.Separator
26496 * @extends Roo.bootstrap.Component
26497 * Bootstrap Separator class
26500 * Create a new Separator
26501 * @param {Object} config The config object
26505 Roo.bootstrap.menu.Separator = function(config){
26506 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26509 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26511 getAutoCreate : function(){
26532 * @class Roo.bootstrap.Tooltip
26533 * Bootstrap Tooltip class
26534 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26535 * to determine which dom element triggers the tooltip.
26537 * It needs to add support for additional attributes like tooltip-position
26540 * Create a new Toolti
26541 * @param {Object} config The config object
26544 Roo.bootstrap.Tooltip = function(config){
26545 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26547 this.alignment = Roo.bootstrap.Tooltip.alignment;
26549 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26550 this.alignment = config.alignment;
26555 Roo.apply(Roo.bootstrap.Tooltip, {
26557 * @function init initialize tooltip monitoring.
26561 currentTip : false,
26562 currentRegion : false,
26568 Roo.get(document).on('mouseover', this.enter ,this);
26569 Roo.get(document).on('mouseout', this.leave, this);
26572 this.currentTip = new Roo.bootstrap.Tooltip();
26575 enter : function(ev)
26577 var dom = ev.getTarget();
26579 //Roo.log(['enter',dom]);
26580 var el = Roo.fly(dom);
26581 if (this.currentEl) {
26583 //Roo.log(this.currentEl);
26584 //Roo.log(this.currentEl.contains(dom));
26585 if (this.currentEl == el) {
26588 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26594 if (this.currentTip.el) {
26595 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26599 if(!el || el.dom == document){
26605 // you can not look for children, as if el is the body.. then everythign is the child..
26606 if (!el.attr('tooltip')) { //
26607 if (!el.select("[tooltip]").elements.length) {
26610 // is the mouse over this child...?
26611 bindEl = el.select("[tooltip]").first();
26612 var xy = ev.getXY();
26613 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26614 //Roo.log("not in region.");
26617 //Roo.log("child element over..");
26620 this.currentEl = bindEl;
26621 this.currentTip.bind(bindEl);
26622 this.currentRegion = Roo.lib.Region.getRegion(dom);
26623 this.currentTip.enter();
26626 leave : function(ev)
26628 var dom = ev.getTarget();
26629 //Roo.log(['leave',dom]);
26630 if (!this.currentEl) {
26635 if (dom != this.currentEl.dom) {
26638 var xy = ev.getXY();
26639 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26642 // only activate leave if mouse cursor is outside... bounding box..
26647 if (this.currentTip) {
26648 this.currentTip.leave();
26650 //Roo.log('clear currentEl');
26651 this.currentEl = false;
26656 'left' : ['r-l', [-2,0], 'right'],
26657 'right' : ['l-r', [2,0], 'left'],
26658 'bottom' : ['t-b', [0,2], 'top'],
26659 'top' : [ 'b-t', [0,-2], 'bottom']
26665 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26670 delay : null, // can be { show : 300 , hide: 500}
26674 hoverState : null, //???
26676 placement : 'bottom',
26680 getAutoCreate : function(){
26687 cls : 'tooltip-arrow'
26690 cls : 'tooltip-inner'
26697 bind : function(el)
26703 enter : function () {
26705 if (this.timeout != null) {
26706 clearTimeout(this.timeout);
26709 this.hoverState = 'in';
26710 //Roo.log("enter - show");
26711 if (!this.delay || !this.delay.show) {
26716 this.timeout = setTimeout(function () {
26717 if (_t.hoverState == 'in') {
26720 }, this.delay.show);
26724 clearTimeout(this.timeout);
26726 this.hoverState = 'out';
26727 if (!this.delay || !this.delay.hide) {
26733 this.timeout = setTimeout(function () {
26734 //Roo.log("leave - timeout");
26736 if (_t.hoverState == 'out') {
26738 Roo.bootstrap.Tooltip.currentEl = false;
26743 show : function (msg)
26746 this.render(document.body);
26749 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26751 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26753 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26755 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26757 var placement = typeof this.placement == 'function' ?
26758 this.placement.call(this, this.el, on_el) :
26761 var autoToken = /\s?auto?\s?/i;
26762 var autoPlace = autoToken.test(placement);
26764 placement = placement.replace(autoToken, '') || 'top';
26768 //this.el.setXY([0,0]);
26770 //this.el.dom.style.display='block';
26772 //this.el.appendTo(on_el);
26774 var p = this.getPosition();
26775 var box = this.el.getBox();
26781 var align = this.alignment[placement];
26783 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26785 if(placement == 'top' || placement == 'bottom'){
26787 placement = 'right';
26790 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26791 placement = 'left';
26794 var scroll = Roo.select('body', true).first().getScroll();
26796 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26800 align = this.alignment[placement];
26803 this.el.alignTo(this.bindEl, align[0],align[1]);
26804 //var arrow = this.el.select('.arrow',true).first();
26805 //arrow.set(align[2],
26807 this.el.addClass(placement);
26809 this.el.addClass('in fade');
26811 this.hoverState = null;
26813 if (this.el.hasClass('fade')) {
26824 //this.el.setXY([0,0]);
26825 this.el.removeClass('in');
26841 * @class Roo.bootstrap.LocationPicker
26842 * @extends Roo.bootstrap.Component
26843 * Bootstrap LocationPicker class
26844 * @cfg {Number} latitude Position when init default 0
26845 * @cfg {Number} longitude Position when init default 0
26846 * @cfg {Number} zoom default 15
26847 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26848 * @cfg {Boolean} mapTypeControl default false
26849 * @cfg {Boolean} disableDoubleClickZoom default false
26850 * @cfg {Boolean} scrollwheel default true
26851 * @cfg {Boolean} streetViewControl default false
26852 * @cfg {Number} radius default 0
26853 * @cfg {String} locationName
26854 * @cfg {Boolean} draggable default true
26855 * @cfg {Boolean} enableAutocomplete default false
26856 * @cfg {Boolean} enableReverseGeocode default true
26857 * @cfg {String} markerTitle
26860 * Create a new LocationPicker
26861 * @param {Object} config The config object
26865 Roo.bootstrap.LocationPicker = function(config){
26867 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26872 * Fires when the picker initialized.
26873 * @param {Roo.bootstrap.LocationPicker} this
26874 * @param {Google Location} location
26878 * @event positionchanged
26879 * Fires when the picker position changed.
26880 * @param {Roo.bootstrap.LocationPicker} this
26881 * @param {Google Location} location
26883 positionchanged : true,
26886 * Fires when the map resize.
26887 * @param {Roo.bootstrap.LocationPicker} this
26892 * Fires when the map show.
26893 * @param {Roo.bootstrap.LocationPicker} this
26898 * Fires when the map hide.
26899 * @param {Roo.bootstrap.LocationPicker} this
26904 * Fires when click the map.
26905 * @param {Roo.bootstrap.LocationPicker} this
26906 * @param {Map event} e
26910 * @event mapRightClick
26911 * Fires when right click the map.
26912 * @param {Roo.bootstrap.LocationPicker} this
26913 * @param {Map event} e
26915 mapRightClick : true,
26917 * @event markerClick
26918 * Fires when click the marker.
26919 * @param {Roo.bootstrap.LocationPicker} this
26920 * @param {Map event} e
26922 markerClick : true,
26924 * @event markerRightClick
26925 * Fires when right click the marker.
26926 * @param {Roo.bootstrap.LocationPicker} this
26927 * @param {Map event} e
26929 markerRightClick : true,
26931 * @event OverlayViewDraw
26932 * Fires when OverlayView Draw
26933 * @param {Roo.bootstrap.LocationPicker} this
26935 OverlayViewDraw : true,
26937 * @event OverlayViewOnAdd
26938 * Fires when OverlayView Draw
26939 * @param {Roo.bootstrap.LocationPicker} this
26941 OverlayViewOnAdd : true,
26943 * @event OverlayViewOnRemove
26944 * Fires when OverlayView Draw
26945 * @param {Roo.bootstrap.LocationPicker} this
26947 OverlayViewOnRemove : true,
26949 * @event OverlayViewShow
26950 * Fires when OverlayView Draw
26951 * @param {Roo.bootstrap.LocationPicker} this
26952 * @param {Pixel} cpx
26954 OverlayViewShow : true,
26956 * @event OverlayViewHide
26957 * Fires when OverlayView Draw
26958 * @param {Roo.bootstrap.LocationPicker} this
26960 OverlayViewHide : true,
26962 * @event loadexception
26963 * Fires when load google lib failed.
26964 * @param {Roo.bootstrap.LocationPicker} this
26966 loadexception : true
26971 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26973 gMapContext: false,
26979 mapTypeControl: false,
26980 disableDoubleClickZoom: false,
26982 streetViewControl: false,
26986 enableAutocomplete: false,
26987 enableReverseGeocode: true,
26990 getAutoCreate: function()
26995 cls: 'roo-location-picker'
27001 initEvents: function(ct, position)
27003 if(!this.el.getWidth() || this.isApplied()){
27007 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27012 initial: function()
27014 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
27015 this.fireEvent('loadexception', this);
27019 if(!this.mapTypeId){
27020 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
27023 this.gMapContext = this.GMapContext();
27025 this.initOverlayView();
27027 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
27031 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
27032 _this.setPosition(_this.gMapContext.marker.position);
27035 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
27036 _this.fireEvent('mapClick', this, event);
27040 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
27041 _this.fireEvent('mapRightClick', this, event);
27045 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
27046 _this.fireEvent('markerClick', this, event);
27050 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
27051 _this.fireEvent('markerRightClick', this, event);
27055 this.setPosition(this.gMapContext.location);
27057 this.fireEvent('initial', this, this.gMapContext.location);
27060 initOverlayView: function()
27064 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27068 _this.fireEvent('OverlayViewDraw', _this);
27073 _this.fireEvent('OverlayViewOnAdd', _this);
27076 onRemove: function()
27078 _this.fireEvent('OverlayViewOnRemove', _this);
27081 show: function(cpx)
27083 _this.fireEvent('OverlayViewShow', _this, cpx);
27088 _this.fireEvent('OverlayViewHide', _this);
27094 fromLatLngToContainerPixel: function(event)
27096 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27099 isApplied: function()
27101 return this.getGmapContext() == false ? false : true;
27104 getGmapContext: function()
27106 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27109 GMapContext: function()
27111 var position = new google.maps.LatLng(this.latitude, this.longitude);
27113 var _map = new google.maps.Map(this.el.dom, {
27116 mapTypeId: this.mapTypeId,
27117 mapTypeControl: this.mapTypeControl,
27118 disableDoubleClickZoom: this.disableDoubleClickZoom,
27119 scrollwheel: this.scrollwheel,
27120 streetViewControl: this.streetViewControl,
27121 locationName: this.locationName,
27122 draggable: this.draggable,
27123 enableAutocomplete: this.enableAutocomplete,
27124 enableReverseGeocode: this.enableReverseGeocode
27127 var _marker = new google.maps.Marker({
27128 position: position,
27130 title: this.markerTitle,
27131 draggable: this.draggable
27138 location: position,
27139 radius: this.radius,
27140 locationName: this.locationName,
27141 addressComponents: {
27142 formatted_address: null,
27143 addressLine1: null,
27144 addressLine2: null,
27146 streetNumber: null,
27150 stateOrProvince: null
27153 domContainer: this.el.dom,
27154 geodecoder: new google.maps.Geocoder()
27158 drawCircle: function(center, radius, options)
27160 if (this.gMapContext.circle != null) {
27161 this.gMapContext.circle.setMap(null);
27165 options = Roo.apply({}, options, {
27166 strokeColor: "#0000FF",
27167 strokeOpacity: .35,
27169 fillColor: "#0000FF",
27173 options.map = this.gMapContext.map;
27174 options.radius = radius;
27175 options.center = center;
27176 this.gMapContext.circle = new google.maps.Circle(options);
27177 return this.gMapContext.circle;
27183 setPosition: function(location)
27185 this.gMapContext.location = location;
27186 this.gMapContext.marker.setPosition(location);
27187 this.gMapContext.map.panTo(location);
27188 this.drawCircle(location, this.gMapContext.radius, {});
27192 if (this.gMapContext.settings.enableReverseGeocode) {
27193 this.gMapContext.geodecoder.geocode({
27194 latLng: this.gMapContext.location
27195 }, function(results, status) {
27197 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27198 _this.gMapContext.locationName = results[0].formatted_address;
27199 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27201 _this.fireEvent('positionchanged', this, location);
27208 this.fireEvent('positionchanged', this, location);
27213 google.maps.event.trigger(this.gMapContext.map, "resize");
27215 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27217 this.fireEvent('resize', this);
27220 setPositionByLatLng: function(latitude, longitude)
27222 this.setPosition(new google.maps.LatLng(latitude, longitude));
27225 getCurrentPosition: function()
27228 latitude: this.gMapContext.location.lat(),
27229 longitude: this.gMapContext.location.lng()
27233 getAddressName: function()
27235 return this.gMapContext.locationName;
27238 getAddressComponents: function()
27240 return this.gMapContext.addressComponents;
27243 address_component_from_google_geocode: function(address_components)
27247 for (var i = 0; i < address_components.length; i++) {
27248 var component = address_components[i];
27249 if (component.types.indexOf("postal_code") >= 0) {
27250 result.postalCode = component.short_name;
27251 } else if (component.types.indexOf("street_number") >= 0) {
27252 result.streetNumber = component.short_name;
27253 } else if (component.types.indexOf("route") >= 0) {
27254 result.streetName = component.short_name;
27255 } else if (component.types.indexOf("neighborhood") >= 0) {
27256 result.city = component.short_name;
27257 } else if (component.types.indexOf("locality") >= 0) {
27258 result.city = component.short_name;
27259 } else if (component.types.indexOf("sublocality") >= 0) {
27260 result.district = component.short_name;
27261 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27262 result.stateOrProvince = component.short_name;
27263 } else if (component.types.indexOf("country") >= 0) {
27264 result.country = component.short_name;
27268 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27269 result.addressLine2 = "";
27273 setZoomLevel: function(zoom)
27275 this.gMapContext.map.setZoom(zoom);
27288 this.fireEvent('show', this);
27299 this.fireEvent('hide', this);
27304 Roo.apply(Roo.bootstrap.LocationPicker, {
27306 OverlayView : function(map, options)
27308 options = options || {};
27315 * @class Roo.bootstrap.Alert
27316 * @extends Roo.bootstrap.Component
27317 * Bootstrap Alert class - shows an alert area box
27319 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27320 Enter a valid email address
27323 * @cfg {String} title The title of alert
27324 * @cfg {String} html The content of alert
27325 * @cfg {String} weight ( success | info | warning | danger )
27326 * @cfg {String} faicon font-awesomeicon
27329 * Create a new alert
27330 * @param {Object} config The config object
27334 Roo.bootstrap.Alert = function(config){
27335 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27339 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27346 getAutoCreate : function()
27355 cls : 'roo-alert-icon'
27360 cls : 'roo-alert-title',
27365 cls : 'roo-alert-text',
27372 cfg.cn[0].cls += ' fa ' + this.faicon;
27376 cfg.cls += ' alert-' + this.weight;
27382 initEvents: function()
27384 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27387 setTitle : function(str)
27389 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27392 setText : function(str)
27394 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27397 setWeight : function(weight)
27400 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27403 this.weight = weight;
27405 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27408 setIcon : function(icon)
27411 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27414 this.faicon = icon;
27416 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27437 * @class Roo.bootstrap.UploadCropbox
27438 * @extends Roo.bootstrap.Component
27439 * Bootstrap UploadCropbox class
27440 * @cfg {String} emptyText show when image has been loaded
27441 * @cfg {String} rotateNotify show when image too small to rotate
27442 * @cfg {Number} errorTimeout default 3000
27443 * @cfg {Number} minWidth default 300
27444 * @cfg {Number} minHeight default 300
27445 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27446 * @cfg {Boolean} isDocument (true|false) default false
27447 * @cfg {String} url action url
27448 * @cfg {String} paramName default 'imageUpload'
27449 * @cfg {String} method default POST
27450 * @cfg {Boolean} loadMask (true|false) default true
27451 * @cfg {Boolean} loadingText default 'Loading...'
27454 * Create a new UploadCropbox
27455 * @param {Object} config The config object
27458 Roo.bootstrap.UploadCropbox = function(config){
27459 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27463 * @event beforeselectfile
27464 * Fire before select file
27465 * @param {Roo.bootstrap.UploadCropbox} this
27467 "beforeselectfile" : true,
27470 * Fire after initEvent
27471 * @param {Roo.bootstrap.UploadCropbox} this
27476 * Fire after initEvent
27477 * @param {Roo.bootstrap.UploadCropbox} this
27478 * @param {String} data
27483 * Fire when preparing the file data
27484 * @param {Roo.bootstrap.UploadCropbox} this
27485 * @param {Object} file
27490 * Fire when get exception
27491 * @param {Roo.bootstrap.UploadCropbox} this
27492 * @param {XMLHttpRequest} xhr
27494 "exception" : true,
27496 * @event beforeloadcanvas
27497 * Fire before load the canvas
27498 * @param {Roo.bootstrap.UploadCropbox} this
27499 * @param {String} src
27501 "beforeloadcanvas" : true,
27504 * Fire when trash image
27505 * @param {Roo.bootstrap.UploadCropbox} this
27510 * Fire when download the image
27511 * @param {Roo.bootstrap.UploadCropbox} this
27515 * @event footerbuttonclick
27516 * Fire when footerbuttonclick
27517 * @param {Roo.bootstrap.UploadCropbox} this
27518 * @param {String} type
27520 "footerbuttonclick" : true,
27524 * @param {Roo.bootstrap.UploadCropbox} this
27529 * Fire when rotate the image
27530 * @param {Roo.bootstrap.UploadCropbox} this
27531 * @param {String} pos
27536 * Fire when inspect the file
27537 * @param {Roo.bootstrap.UploadCropbox} this
27538 * @param {Object} file
27543 * Fire when xhr upload the file
27544 * @param {Roo.bootstrap.UploadCropbox} this
27545 * @param {Object} data
27550 * Fire when arrange the file data
27551 * @param {Roo.bootstrap.UploadCropbox} this
27552 * @param {Object} formData
27557 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27560 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27562 emptyText : 'Click to upload image',
27563 rotateNotify : 'Image is too small to rotate',
27564 errorTimeout : 3000,
27578 cropType : 'image/jpeg',
27580 canvasLoaded : false,
27581 isDocument : false,
27583 paramName : 'imageUpload',
27585 loadingText : 'Loading...',
27588 getAutoCreate : function()
27592 cls : 'roo-upload-cropbox',
27596 cls : 'roo-upload-cropbox-selector',
27601 cls : 'roo-upload-cropbox-body',
27602 style : 'cursor:pointer',
27606 cls : 'roo-upload-cropbox-preview'
27610 cls : 'roo-upload-cropbox-thumb'
27614 cls : 'roo-upload-cropbox-empty-notify',
27615 html : this.emptyText
27619 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27620 html : this.rotateNotify
27626 cls : 'roo-upload-cropbox-footer',
27629 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27639 onRender : function(ct, position)
27641 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27643 if (this.buttons.length) {
27645 Roo.each(this.buttons, function(bb) {
27647 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27649 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27655 this.maskEl = this.el;
27659 initEvents : function()
27661 this.urlAPI = (window.createObjectURL && window) ||
27662 (window.URL && URL.revokeObjectURL && URL) ||
27663 (window.webkitURL && webkitURL);
27665 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27666 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27668 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27669 this.selectorEl.hide();
27671 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27672 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27674 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27675 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27676 this.thumbEl.hide();
27678 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27679 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27681 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27682 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27683 this.errorEl.hide();
27685 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27686 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27687 this.footerEl.hide();
27689 this.setThumbBoxSize();
27695 this.fireEvent('initial', this);
27702 window.addEventListener("resize", function() { _this.resize(); } );
27704 this.bodyEl.on('click', this.beforeSelectFile, this);
27707 this.bodyEl.on('touchstart', this.onTouchStart, this);
27708 this.bodyEl.on('touchmove', this.onTouchMove, this);
27709 this.bodyEl.on('touchend', this.onTouchEnd, this);
27713 this.bodyEl.on('mousedown', this.onMouseDown, this);
27714 this.bodyEl.on('mousemove', this.onMouseMove, this);
27715 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27716 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27717 Roo.get(document).on('mouseup', this.onMouseUp, this);
27720 this.selectorEl.on('change', this.onFileSelected, this);
27726 this.baseScale = 1;
27728 this.baseRotate = 1;
27729 this.dragable = false;
27730 this.pinching = false;
27733 this.cropData = false;
27734 this.notifyEl.dom.innerHTML = this.emptyText;
27736 this.selectorEl.dom.value = '';
27740 resize : function()
27742 if(this.fireEvent('resize', this) != false){
27743 this.setThumbBoxPosition();
27744 this.setCanvasPosition();
27748 onFooterButtonClick : function(e, el, o, type)
27751 case 'rotate-left' :
27752 this.onRotateLeft(e);
27754 case 'rotate-right' :
27755 this.onRotateRight(e);
27758 this.beforeSelectFile(e);
27773 this.fireEvent('footerbuttonclick', this, type);
27776 beforeSelectFile : function(e)
27778 e.preventDefault();
27780 if(this.fireEvent('beforeselectfile', this) != false){
27781 this.selectorEl.dom.click();
27785 onFileSelected : function(e)
27787 e.preventDefault();
27789 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27793 var file = this.selectorEl.dom.files[0];
27795 if(this.fireEvent('inspect', this, file) != false){
27796 this.prepare(file);
27801 trash : function(e)
27803 this.fireEvent('trash', this);
27806 download : function(e)
27808 this.fireEvent('download', this);
27811 loadCanvas : function(src)
27813 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27817 this.imageEl = document.createElement('img');
27821 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27823 this.imageEl.src = src;
27827 onLoadCanvas : function()
27829 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27830 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27832 this.bodyEl.un('click', this.beforeSelectFile, this);
27834 this.notifyEl.hide();
27835 this.thumbEl.show();
27836 this.footerEl.show();
27838 this.baseRotateLevel();
27840 if(this.isDocument){
27841 this.setThumbBoxSize();
27844 this.setThumbBoxPosition();
27846 this.baseScaleLevel();
27852 this.canvasLoaded = true;
27855 this.maskEl.unmask();
27860 setCanvasPosition : function()
27862 if(!this.canvasEl){
27866 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27867 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27869 this.previewEl.setLeft(pw);
27870 this.previewEl.setTop(ph);
27874 onMouseDown : function(e)
27878 this.dragable = true;
27879 this.pinching = false;
27881 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27882 this.dragable = false;
27886 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27887 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27891 onMouseMove : function(e)
27895 if(!this.canvasLoaded){
27899 if (!this.dragable){
27903 var minX = Math.ceil(this.thumbEl.getLeft(true));
27904 var minY = Math.ceil(this.thumbEl.getTop(true));
27906 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27907 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27909 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27910 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27912 x = x - this.mouseX;
27913 y = y - this.mouseY;
27915 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27916 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27918 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27919 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27921 this.previewEl.setLeft(bgX);
27922 this.previewEl.setTop(bgY);
27924 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27925 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27928 onMouseUp : function(e)
27932 this.dragable = false;
27935 onMouseWheel : function(e)
27939 this.startScale = this.scale;
27941 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27943 if(!this.zoomable()){
27944 this.scale = this.startScale;
27953 zoomable : function()
27955 var minScale = this.thumbEl.getWidth() / this.minWidth;
27957 if(this.minWidth < this.minHeight){
27958 minScale = this.thumbEl.getHeight() / this.minHeight;
27961 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27962 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27966 (this.rotate == 0 || this.rotate == 180) &&
27968 width > this.imageEl.OriginWidth ||
27969 height > this.imageEl.OriginHeight ||
27970 (width < this.minWidth && height < this.minHeight)
27978 (this.rotate == 90 || this.rotate == 270) &&
27980 width > this.imageEl.OriginWidth ||
27981 height > this.imageEl.OriginHeight ||
27982 (width < this.minHeight && height < this.minWidth)
27989 !this.isDocument &&
27990 (this.rotate == 0 || this.rotate == 180) &&
27992 width < this.minWidth ||
27993 width > this.imageEl.OriginWidth ||
27994 height < this.minHeight ||
27995 height > this.imageEl.OriginHeight
28002 !this.isDocument &&
28003 (this.rotate == 90 || this.rotate == 270) &&
28005 width < this.minHeight ||
28006 width > this.imageEl.OriginWidth ||
28007 height < this.minWidth ||
28008 height > this.imageEl.OriginHeight
28018 onRotateLeft : function(e)
28020 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28022 var minScale = this.thumbEl.getWidth() / this.minWidth;
28024 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28025 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28027 this.startScale = this.scale;
28029 while (this.getScaleLevel() < minScale){
28031 this.scale = this.scale + 1;
28033 if(!this.zoomable()){
28038 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28039 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28044 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28051 this.scale = this.startScale;
28053 this.onRotateFail();
28058 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28060 if(this.isDocument){
28061 this.setThumbBoxSize();
28062 this.setThumbBoxPosition();
28063 this.setCanvasPosition();
28068 this.fireEvent('rotate', this, 'left');
28072 onRotateRight : function(e)
28074 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28076 var minScale = this.thumbEl.getWidth() / this.minWidth;
28078 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28079 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28081 this.startScale = this.scale;
28083 while (this.getScaleLevel() < minScale){
28085 this.scale = this.scale + 1;
28087 if(!this.zoomable()){
28092 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28093 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28098 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28105 this.scale = this.startScale;
28107 this.onRotateFail();
28112 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28114 if(this.isDocument){
28115 this.setThumbBoxSize();
28116 this.setThumbBoxPosition();
28117 this.setCanvasPosition();
28122 this.fireEvent('rotate', this, 'right');
28125 onRotateFail : function()
28127 this.errorEl.show(true);
28131 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28136 this.previewEl.dom.innerHTML = '';
28138 var canvasEl = document.createElement("canvas");
28140 var contextEl = canvasEl.getContext("2d");
28142 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28143 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28144 var center = this.imageEl.OriginWidth / 2;
28146 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28147 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28148 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28149 center = this.imageEl.OriginHeight / 2;
28152 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28154 contextEl.translate(center, center);
28155 contextEl.rotate(this.rotate * Math.PI / 180);
28157 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28159 this.canvasEl = document.createElement("canvas");
28161 this.contextEl = this.canvasEl.getContext("2d");
28163 switch (this.rotate) {
28166 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28167 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28169 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28174 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28175 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28177 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28178 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);
28182 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28187 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28188 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28190 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28191 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);
28195 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);
28200 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28201 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28203 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28204 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28208 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);
28215 this.previewEl.appendChild(this.canvasEl);
28217 this.setCanvasPosition();
28222 if(!this.canvasLoaded){
28226 var imageCanvas = document.createElement("canvas");
28228 var imageContext = imageCanvas.getContext("2d");
28230 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28231 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28233 var center = imageCanvas.width / 2;
28235 imageContext.translate(center, center);
28237 imageContext.rotate(this.rotate * Math.PI / 180);
28239 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28241 var canvas = document.createElement("canvas");
28243 var context = canvas.getContext("2d");
28245 canvas.width = this.minWidth;
28246 canvas.height = this.minHeight;
28248 switch (this.rotate) {
28251 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28252 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28254 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28255 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28257 var targetWidth = this.minWidth - 2 * x;
28258 var targetHeight = this.minHeight - 2 * y;
28262 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28263 scale = targetWidth / width;
28266 if(x > 0 && y == 0){
28267 scale = targetHeight / height;
28270 if(x > 0 && y > 0){
28271 scale = targetWidth / width;
28273 if(width < height){
28274 scale = targetHeight / height;
28278 context.scale(scale, scale);
28280 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28281 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28283 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28284 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28286 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28291 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28292 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28294 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28295 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28297 var targetWidth = this.minWidth - 2 * x;
28298 var targetHeight = this.minHeight - 2 * y;
28302 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28303 scale = targetWidth / width;
28306 if(x > 0 && y == 0){
28307 scale = targetHeight / height;
28310 if(x > 0 && y > 0){
28311 scale = targetWidth / width;
28313 if(width < height){
28314 scale = targetHeight / height;
28318 context.scale(scale, scale);
28320 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28321 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28323 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28324 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28326 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28328 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28333 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28334 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28336 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28337 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28339 var targetWidth = this.minWidth - 2 * x;
28340 var targetHeight = this.minHeight - 2 * y;
28344 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28345 scale = targetWidth / width;
28348 if(x > 0 && y == 0){
28349 scale = targetHeight / height;
28352 if(x > 0 && y > 0){
28353 scale = targetWidth / width;
28355 if(width < height){
28356 scale = targetHeight / height;
28360 context.scale(scale, scale);
28362 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28363 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28365 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28366 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28368 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28369 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28371 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28376 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28377 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28379 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28380 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28382 var targetWidth = this.minWidth - 2 * x;
28383 var targetHeight = this.minHeight - 2 * y;
28387 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28388 scale = targetWidth / width;
28391 if(x > 0 && y == 0){
28392 scale = targetHeight / height;
28395 if(x > 0 && y > 0){
28396 scale = targetWidth / width;
28398 if(width < height){
28399 scale = targetHeight / height;
28403 context.scale(scale, scale);
28405 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28406 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28408 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28409 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28411 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28413 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28420 this.cropData = canvas.toDataURL(this.cropType);
28422 if(this.fireEvent('crop', this, this.cropData) !== false){
28423 this.process(this.file, this.cropData);
28430 setThumbBoxSize : function()
28434 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28435 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28436 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28438 this.minWidth = width;
28439 this.minHeight = height;
28441 if(this.rotate == 90 || this.rotate == 270){
28442 this.minWidth = height;
28443 this.minHeight = width;
28448 width = Math.ceil(this.minWidth * height / this.minHeight);
28450 if(this.minWidth > this.minHeight){
28452 height = Math.ceil(this.minHeight * width / this.minWidth);
28455 this.thumbEl.setStyle({
28456 width : width + 'px',
28457 height : height + 'px'
28464 setThumbBoxPosition : function()
28466 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28467 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28469 this.thumbEl.setLeft(x);
28470 this.thumbEl.setTop(y);
28474 baseRotateLevel : function()
28476 this.baseRotate = 1;
28479 typeof(this.exif) != 'undefined' &&
28480 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28481 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28483 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28486 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28490 baseScaleLevel : function()
28494 if(this.isDocument){
28496 if(this.baseRotate == 6 || this.baseRotate == 8){
28498 height = this.thumbEl.getHeight();
28499 this.baseScale = height / this.imageEl.OriginWidth;
28501 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28502 width = this.thumbEl.getWidth();
28503 this.baseScale = width / this.imageEl.OriginHeight;
28509 height = this.thumbEl.getHeight();
28510 this.baseScale = height / this.imageEl.OriginHeight;
28512 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28513 width = this.thumbEl.getWidth();
28514 this.baseScale = width / this.imageEl.OriginWidth;
28520 if(this.baseRotate == 6 || this.baseRotate == 8){
28522 width = this.thumbEl.getHeight();
28523 this.baseScale = width / this.imageEl.OriginHeight;
28525 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28526 height = this.thumbEl.getWidth();
28527 this.baseScale = height / this.imageEl.OriginHeight;
28530 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28531 height = this.thumbEl.getWidth();
28532 this.baseScale = height / this.imageEl.OriginHeight;
28534 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28535 width = this.thumbEl.getHeight();
28536 this.baseScale = width / this.imageEl.OriginWidth;
28543 width = this.thumbEl.getWidth();
28544 this.baseScale = width / this.imageEl.OriginWidth;
28546 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28547 height = this.thumbEl.getHeight();
28548 this.baseScale = height / this.imageEl.OriginHeight;
28551 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28553 height = this.thumbEl.getHeight();
28554 this.baseScale = height / this.imageEl.OriginHeight;
28556 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28557 width = this.thumbEl.getWidth();
28558 this.baseScale = width / this.imageEl.OriginWidth;
28566 getScaleLevel : function()
28568 return this.baseScale * Math.pow(1.1, this.scale);
28571 onTouchStart : function(e)
28573 if(!this.canvasLoaded){
28574 this.beforeSelectFile(e);
28578 var touches = e.browserEvent.touches;
28584 if(touches.length == 1){
28585 this.onMouseDown(e);
28589 if(touches.length != 2){
28595 for(var i = 0, finger; finger = touches[i]; i++){
28596 coords.push(finger.pageX, finger.pageY);
28599 var x = Math.pow(coords[0] - coords[2], 2);
28600 var y = Math.pow(coords[1] - coords[3], 2);
28602 this.startDistance = Math.sqrt(x + y);
28604 this.startScale = this.scale;
28606 this.pinching = true;
28607 this.dragable = false;
28611 onTouchMove : function(e)
28613 if(!this.pinching && !this.dragable){
28617 var touches = e.browserEvent.touches;
28624 this.onMouseMove(e);
28630 for(var i = 0, finger; finger = touches[i]; i++){
28631 coords.push(finger.pageX, finger.pageY);
28634 var x = Math.pow(coords[0] - coords[2], 2);
28635 var y = Math.pow(coords[1] - coords[3], 2);
28637 this.endDistance = Math.sqrt(x + y);
28639 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28641 if(!this.zoomable()){
28642 this.scale = this.startScale;
28650 onTouchEnd : function(e)
28652 this.pinching = false;
28653 this.dragable = false;
28657 process : function(file, crop)
28660 this.maskEl.mask(this.loadingText);
28663 this.xhr = new XMLHttpRequest();
28665 file.xhr = this.xhr;
28667 this.xhr.open(this.method, this.url, true);
28670 "Accept": "application/json",
28671 "Cache-Control": "no-cache",
28672 "X-Requested-With": "XMLHttpRequest"
28675 for (var headerName in headers) {
28676 var headerValue = headers[headerName];
28678 this.xhr.setRequestHeader(headerName, headerValue);
28684 this.xhr.onload = function()
28686 _this.xhrOnLoad(_this.xhr);
28689 this.xhr.onerror = function()
28691 _this.xhrOnError(_this.xhr);
28694 var formData = new FormData();
28696 formData.append('returnHTML', 'NO');
28699 formData.append('crop', crop);
28702 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28703 formData.append(this.paramName, file, file.name);
28706 if(typeof(file.filename) != 'undefined'){
28707 formData.append('filename', file.filename);
28710 if(typeof(file.mimetype) != 'undefined'){
28711 formData.append('mimetype', file.mimetype);
28714 if(this.fireEvent('arrange', this, formData) != false){
28715 this.xhr.send(formData);
28719 xhrOnLoad : function(xhr)
28722 this.maskEl.unmask();
28725 if (xhr.readyState !== 4) {
28726 this.fireEvent('exception', this, xhr);
28730 var response = Roo.decode(xhr.responseText);
28732 if(!response.success){
28733 this.fireEvent('exception', this, xhr);
28737 var response = Roo.decode(xhr.responseText);
28739 this.fireEvent('upload', this, response);
28743 xhrOnError : function()
28746 this.maskEl.unmask();
28749 Roo.log('xhr on error');
28751 var response = Roo.decode(xhr.responseText);
28757 prepare : function(file)
28760 this.maskEl.mask(this.loadingText);
28766 if(typeof(file) === 'string'){
28767 this.loadCanvas(file);
28771 if(!file || !this.urlAPI){
28776 this.cropType = file.type;
28780 if(this.fireEvent('prepare', this, this.file) != false){
28782 var reader = new FileReader();
28784 reader.onload = function (e) {
28785 if (e.target.error) {
28786 Roo.log(e.target.error);
28790 var buffer = e.target.result,
28791 dataView = new DataView(buffer),
28793 maxOffset = dataView.byteLength - 4,
28797 if (dataView.getUint16(0) === 0xffd8) {
28798 while (offset < maxOffset) {
28799 markerBytes = dataView.getUint16(offset);
28801 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28802 markerLength = dataView.getUint16(offset + 2) + 2;
28803 if (offset + markerLength > dataView.byteLength) {
28804 Roo.log('Invalid meta data: Invalid segment size.');
28808 if(markerBytes == 0xffe1){
28809 _this.parseExifData(
28816 offset += markerLength;
28826 var url = _this.urlAPI.createObjectURL(_this.file);
28828 _this.loadCanvas(url);
28833 reader.readAsArrayBuffer(this.file);
28839 parseExifData : function(dataView, offset, length)
28841 var tiffOffset = offset + 10,
28845 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28846 // No Exif data, might be XMP data instead
28850 // Check for the ASCII code for "Exif" (0x45786966):
28851 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28852 // No Exif data, might be XMP data instead
28855 if (tiffOffset + 8 > dataView.byteLength) {
28856 Roo.log('Invalid Exif data: Invalid segment size.');
28859 // Check for the two null bytes:
28860 if (dataView.getUint16(offset + 8) !== 0x0000) {
28861 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28864 // Check the byte alignment:
28865 switch (dataView.getUint16(tiffOffset)) {
28867 littleEndian = true;
28870 littleEndian = false;
28873 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28876 // Check for the TIFF tag marker (0x002A):
28877 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28878 Roo.log('Invalid Exif data: Missing TIFF marker.');
28881 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28882 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28884 this.parseExifTags(
28887 tiffOffset + dirOffset,
28892 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28897 if (dirOffset + 6 > dataView.byteLength) {
28898 Roo.log('Invalid Exif data: Invalid directory offset.');
28901 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28902 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28903 if (dirEndOffset + 4 > dataView.byteLength) {
28904 Roo.log('Invalid Exif data: Invalid directory size.');
28907 for (i = 0; i < tagsNumber; i += 1) {
28911 dirOffset + 2 + 12 * i, // tag offset
28915 // Return the offset to the next directory:
28916 return dataView.getUint32(dirEndOffset, littleEndian);
28919 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28921 var tag = dataView.getUint16(offset, littleEndian);
28923 this.exif[tag] = this.getExifValue(
28927 dataView.getUint16(offset + 2, littleEndian), // tag type
28928 dataView.getUint32(offset + 4, littleEndian), // tag length
28933 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28935 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28944 Roo.log('Invalid Exif data: Invalid tag type.');
28948 tagSize = tagType.size * length;
28949 // Determine if the value is contained in the dataOffset bytes,
28950 // or if the value at the dataOffset is a pointer to the actual data:
28951 dataOffset = tagSize > 4 ?
28952 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28953 if (dataOffset + tagSize > dataView.byteLength) {
28954 Roo.log('Invalid Exif data: Invalid data offset.');
28957 if (length === 1) {
28958 return tagType.getValue(dataView, dataOffset, littleEndian);
28961 for (i = 0; i < length; i += 1) {
28962 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28965 if (tagType.ascii) {
28967 // Concatenate the chars:
28968 for (i = 0; i < values.length; i += 1) {
28970 // Ignore the terminating NULL byte(s):
28971 if (c === '\u0000') {
28983 Roo.apply(Roo.bootstrap.UploadCropbox, {
28985 'Orientation': 0x0112
28989 1: 0, //'top-left',
28991 3: 180, //'bottom-right',
28992 // 4: 'bottom-left',
28994 6: 90, //'right-top',
28995 // 7: 'right-bottom',
28996 8: 270 //'left-bottom'
29000 // byte, 8-bit unsigned int:
29002 getValue: function (dataView, dataOffset) {
29003 return dataView.getUint8(dataOffset);
29007 // ascii, 8-bit byte:
29009 getValue: function (dataView, dataOffset) {
29010 return String.fromCharCode(dataView.getUint8(dataOffset));
29015 // short, 16 bit int:
29017 getValue: function (dataView, dataOffset, littleEndian) {
29018 return dataView.getUint16(dataOffset, littleEndian);
29022 // long, 32 bit int:
29024 getValue: function (dataView, dataOffset, littleEndian) {
29025 return dataView.getUint32(dataOffset, littleEndian);
29029 // rational = two long values, first is numerator, second is denominator:
29031 getValue: function (dataView, dataOffset, littleEndian) {
29032 return dataView.getUint32(dataOffset, littleEndian) /
29033 dataView.getUint32(dataOffset + 4, littleEndian);
29037 // slong, 32 bit signed int:
29039 getValue: function (dataView, dataOffset, littleEndian) {
29040 return dataView.getInt32(dataOffset, littleEndian);
29044 // srational, two slongs, first is numerator, second is denominator:
29046 getValue: function (dataView, dataOffset, littleEndian) {
29047 return dataView.getInt32(dataOffset, littleEndian) /
29048 dataView.getInt32(dataOffset + 4, littleEndian);
29058 cls : 'btn-group roo-upload-cropbox-rotate-left',
29059 action : 'rotate-left',
29063 cls : 'btn btn-default',
29064 html : '<i class="fa fa-undo"></i>'
29070 cls : 'btn-group roo-upload-cropbox-picture',
29071 action : 'picture',
29075 cls : 'btn btn-default',
29076 html : '<i class="fa fa-picture-o"></i>'
29082 cls : 'btn-group roo-upload-cropbox-rotate-right',
29083 action : 'rotate-right',
29087 cls : 'btn btn-default',
29088 html : '<i class="fa fa-repeat"></i>'
29096 cls : 'btn-group roo-upload-cropbox-rotate-left',
29097 action : 'rotate-left',
29101 cls : 'btn btn-default',
29102 html : '<i class="fa fa-undo"></i>'
29108 cls : 'btn-group roo-upload-cropbox-download',
29109 action : 'download',
29113 cls : 'btn btn-default',
29114 html : '<i class="fa fa-download"></i>'
29120 cls : 'btn-group roo-upload-cropbox-crop',
29125 cls : 'btn btn-default',
29126 html : '<i class="fa fa-crop"></i>'
29132 cls : 'btn-group roo-upload-cropbox-trash',
29137 cls : 'btn btn-default',
29138 html : '<i class="fa fa-trash"></i>'
29144 cls : 'btn-group roo-upload-cropbox-rotate-right',
29145 action : 'rotate-right',
29149 cls : 'btn btn-default',
29150 html : '<i class="fa fa-repeat"></i>'
29158 cls : 'btn-group roo-upload-cropbox-rotate-left',
29159 action : 'rotate-left',
29163 cls : 'btn btn-default',
29164 html : '<i class="fa fa-undo"></i>'
29170 cls : 'btn-group roo-upload-cropbox-rotate-right',
29171 action : 'rotate-right',
29175 cls : 'btn btn-default',
29176 html : '<i class="fa fa-repeat"></i>'
29189 * @class Roo.bootstrap.DocumentManager
29190 * @extends Roo.bootstrap.Component
29191 * Bootstrap DocumentManager class
29192 * @cfg {String} paramName default 'imageUpload'
29193 * @cfg {String} toolTipName default 'filename'
29194 * @cfg {String} method default POST
29195 * @cfg {String} url action url
29196 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29197 * @cfg {Boolean} multiple multiple upload default true
29198 * @cfg {Number} thumbSize default 300
29199 * @cfg {String} fieldLabel
29200 * @cfg {Number} labelWidth default 4
29201 * @cfg {String} labelAlign (left|top) default left
29202 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29203 * @cfg {Number} labellg set the width of label (1-12)
29204 * @cfg {Number} labelmd set the width of label (1-12)
29205 * @cfg {Number} labelsm set the width of label (1-12)
29206 * @cfg {Number} labelxs set the width of label (1-12)
29209 * Create a new DocumentManager
29210 * @param {Object} config The config object
29213 Roo.bootstrap.DocumentManager = function(config){
29214 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29217 this.delegates = [];
29222 * Fire when initial the DocumentManager
29223 * @param {Roo.bootstrap.DocumentManager} this
29228 * inspect selected file
29229 * @param {Roo.bootstrap.DocumentManager} this
29230 * @param {File} file
29235 * Fire when xhr load exception
29236 * @param {Roo.bootstrap.DocumentManager} this
29237 * @param {XMLHttpRequest} xhr
29239 "exception" : true,
29241 * @event afterupload
29242 * Fire when xhr load exception
29243 * @param {Roo.bootstrap.DocumentManager} this
29244 * @param {XMLHttpRequest} xhr
29246 "afterupload" : true,
29249 * prepare the form data
29250 * @param {Roo.bootstrap.DocumentManager} this
29251 * @param {Object} formData
29256 * Fire when remove the file
29257 * @param {Roo.bootstrap.DocumentManager} this
29258 * @param {Object} file
29263 * Fire after refresh the file
29264 * @param {Roo.bootstrap.DocumentManager} this
29269 * Fire after click the image
29270 * @param {Roo.bootstrap.DocumentManager} this
29271 * @param {Object} file
29276 * Fire when upload a image and editable set to true
29277 * @param {Roo.bootstrap.DocumentManager} this
29278 * @param {Object} file
29282 * @event beforeselectfile
29283 * Fire before select file
29284 * @param {Roo.bootstrap.DocumentManager} this
29286 "beforeselectfile" : true,
29289 * Fire before process file
29290 * @param {Roo.bootstrap.DocumentManager} this
29291 * @param {Object} file
29295 * @event previewrendered
29296 * Fire when preview rendered
29297 * @param {Roo.bootstrap.DocumentManager} this
29298 * @param {Object} file
29300 "previewrendered" : true,
29303 "previewResize" : true
29308 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29317 paramName : 'imageUpload',
29318 toolTipName : 'filename',
29321 labelAlign : 'left',
29331 getAutoCreate : function()
29333 var managerWidget = {
29335 cls : 'roo-document-manager',
29339 cls : 'roo-document-manager-selector',
29344 cls : 'roo-document-manager-uploader',
29348 cls : 'roo-document-manager-upload-btn',
29349 html : '<i class="fa fa-plus"></i>'
29360 cls : 'column col-md-12',
29365 if(this.fieldLabel.length){
29370 cls : 'column col-md-12',
29371 html : this.fieldLabel
29375 cls : 'column col-md-12',
29380 if(this.labelAlign == 'left'){
29385 html : this.fieldLabel
29394 if(this.labelWidth > 12){
29395 content[0].style = "width: " + this.labelWidth + 'px';
29398 if(this.labelWidth < 13 && this.labelmd == 0){
29399 this.labelmd = this.labelWidth;
29402 if(this.labellg > 0){
29403 content[0].cls += ' col-lg-' + this.labellg;
29404 content[1].cls += ' col-lg-' + (12 - this.labellg);
29407 if(this.labelmd > 0){
29408 content[0].cls += ' col-md-' + this.labelmd;
29409 content[1].cls += ' col-md-' + (12 - this.labelmd);
29412 if(this.labelsm > 0){
29413 content[0].cls += ' col-sm-' + this.labelsm;
29414 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29417 if(this.labelxs > 0){
29418 content[0].cls += ' col-xs-' + this.labelxs;
29419 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29427 cls : 'row clearfix',
29435 initEvents : function()
29437 this.managerEl = this.el.select('.roo-document-manager', true).first();
29438 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29440 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29441 this.selectorEl.hide();
29444 this.selectorEl.attr('multiple', 'multiple');
29447 this.selectorEl.on('change', this.onFileSelected, this);
29449 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29450 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29452 this.uploader.on('click', this.onUploaderClick, this);
29454 this.renderProgressDialog();
29458 window.addEventListener("resize", function() { _this.refresh(); } );
29460 this.fireEvent('initial', this);
29463 renderProgressDialog : function()
29467 this.progressDialog = new Roo.bootstrap.Modal({
29468 cls : 'roo-document-manager-progress-dialog',
29469 allow_close : false,
29480 btnclick : function() {
29481 _this.uploadCancel();
29487 this.progressDialog.render(Roo.get(document.body));
29489 this.progress = new Roo.bootstrap.Progress({
29490 cls : 'roo-document-manager-progress',
29495 this.progress.render(this.progressDialog.getChildContainer());
29497 this.progressBar = new Roo.bootstrap.ProgressBar({
29498 cls : 'roo-document-manager-progress-bar',
29501 aria_valuemax : 12,
29505 this.progressBar.render(this.progress.getChildContainer());
29508 onUploaderClick : function(e)
29510 e.preventDefault();
29512 if(this.fireEvent('beforeselectfile', this) != false){
29513 this.selectorEl.dom.click();
29518 onFileSelected : function(e)
29520 e.preventDefault();
29522 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29526 Roo.each(this.selectorEl.dom.files, function(file){
29527 if(this.fireEvent('inspect', this, file) != false){
29528 this.files.push(file);
29538 this.selectorEl.dom.value = '';
29540 if(!this.files || !this.files.length){
29544 if(this.boxes > 0 && this.files.length > this.boxes){
29545 this.files = this.files.slice(0, this.boxes);
29548 this.uploader.show();
29550 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29551 this.uploader.hide();
29560 Roo.each(this.files, function(file){
29562 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29563 var f = this.renderPreview(file);
29568 if(file.type.indexOf('image') != -1){
29569 this.delegates.push(
29571 _this.process(file);
29572 }).createDelegate(this)
29580 _this.process(file);
29581 }).createDelegate(this)
29586 this.files = files;
29588 this.delegates = this.delegates.concat(docs);
29590 if(!this.delegates.length){
29595 this.progressBar.aria_valuemax = this.delegates.length;
29602 arrange : function()
29604 if(!this.delegates.length){
29605 this.progressDialog.hide();
29610 var delegate = this.delegates.shift();
29612 this.progressDialog.show();
29614 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29616 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29621 refresh : function()
29623 this.uploader.show();
29625 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29626 this.uploader.hide();
29629 Roo.isTouch ? this.closable(false) : this.closable(true);
29631 this.fireEvent('refresh', this);
29634 onRemove : function(e, el, o)
29636 e.preventDefault();
29638 this.fireEvent('remove', this, o);
29642 remove : function(o)
29646 Roo.each(this.files, function(file){
29647 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29656 this.files = files;
29663 Roo.each(this.files, function(file){
29668 file.target.remove();
29677 onClick : function(e, el, o)
29679 e.preventDefault();
29681 this.fireEvent('click', this, o);
29685 closable : function(closable)
29687 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29689 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29701 xhrOnLoad : function(xhr)
29703 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29707 if (xhr.readyState !== 4) {
29709 this.fireEvent('exception', this, xhr);
29713 var response = Roo.decode(xhr.responseText);
29715 if(!response.success){
29717 this.fireEvent('exception', this, xhr);
29721 var file = this.renderPreview(response.data);
29723 this.files.push(file);
29727 this.fireEvent('afterupload', this, xhr);
29731 xhrOnError : function(xhr)
29733 Roo.log('xhr on error');
29735 var response = Roo.decode(xhr.responseText);
29742 process : function(file)
29744 if(this.fireEvent('process', this, file) !== false){
29745 if(this.editable && file.type.indexOf('image') != -1){
29746 this.fireEvent('edit', this, file);
29750 this.uploadStart(file, false);
29757 uploadStart : function(file, crop)
29759 this.xhr = new XMLHttpRequest();
29761 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29766 file.xhr = this.xhr;
29768 this.managerEl.createChild({
29770 cls : 'roo-document-manager-loading',
29774 tooltip : file.name,
29775 cls : 'roo-document-manager-thumb',
29776 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29782 this.xhr.open(this.method, this.url, true);
29785 "Accept": "application/json",
29786 "Cache-Control": "no-cache",
29787 "X-Requested-With": "XMLHttpRequest"
29790 for (var headerName in headers) {
29791 var headerValue = headers[headerName];
29793 this.xhr.setRequestHeader(headerName, headerValue);
29799 this.xhr.onload = function()
29801 _this.xhrOnLoad(_this.xhr);
29804 this.xhr.onerror = function()
29806 _this.xhrOnError(_this.xhr);
29809 var formData = new FormData();
29811 formData.append('returnHTML', 'NO');
29814 formData.append('crop', crop);
29817 formData.append(this.paramName, file, file.name);
29824 if(this.fireEvent('prepare', this, formData, options) != false){
29826 if(options.manually){
29830 this.xhr.send(formData);
29834 this.uploadCancel();
29837 uploadCancel : function()
29843 this.delegates = [];
29845 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29852 renderPreview : function(file)
29854 if(typeof(file.target) != 'undefined' && file.target){
29858 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29860 var previewEl = this.managerEl.createChild({
29862 cls : 'roo-document-manager-preview',
29866 tooltip : file[this.toolTipName],
29867 cls : 'roo-document-manager-thumb',
29868 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29873 html : '<i class="fa fa-times-circle"></i>'
29878 var close = previewEl.select('button.close', true).first();
29880 close.on('click', this.onRemove, this, file);
29882 file.target = previewEl;
29884 var image = previewEl.select('img', true).first();
29888 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29890 image.on('click', this.onClick, this, file);
29892 this.fireEvent('previewrendered', this, file);
29898 onPreviewLoad : function(file, image)
29900 if(typeof(file.target) == 'undefined' || !file.target){
29904 var width = image.dom.naturalWidth || image.dom.width;
29905 var height = image.dom.naturalHeight || image.dom.height;
29907 if(!this.previewResize) {
29911 if(width > height){
29912 file.target.addClass('wide');
29916 file.target.addClass('tall');
29921 uploadFromSource : function(file, crop)
29923 this.xhr = new XMLHttpRequest();
29925 this.managerEl.createChild({
29927 cls : 'roo-document-manager-loading',
29931 tooltip : file.name,
29932 cls : 'roo-document-manager-thumb',
29933 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29939 this.xhr.open(this.method, this.url, true);
29942 "Accept": "application/json",
29943 "Cache-Control": "no-cache",
29944 "X-Requested-With": "XMLHttpRequest"
29947 for (var headerName in headers) {
29948 var headerValue = headers[headerName];
29950 this.xhr.setRequestHeader(headerName, headerValue);
29956 this.xhr.onload = function()
29958 _this.xhrOnLoad(_this.xhr);
29961 this.xhr.onerror = function()
29963 _this.xhrOnError(_this.xhr);
29966 var formData = new FormData();
29968 formData.append('returnHTML', 'NO');
29970 formData.append('crop', crop);
29972 if(typeof(file.filename) != 'undefined'){
29973 formData.append('filename', file.filename);
29976 if(typeof(file.mimetype) != 'undefined'){
29977 formData.append('mimetype', file.mimetype);
29982 if(this.fireEvent('prepare', this, formData) != false){
29983 this.xhr.send(formData);
29993 * @class Roo.bootstrap.DocumentViewer
29994 * @extends Roo.bootstrap.Component
29995 * Bootstrap DocumentViewer class
29996 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29997 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
30000 * Create a new DocumentViewer
30001 * @param {Object} config The config object
30004 Roo.bootstrap.DocumentViewer = function(config){
30005 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
30010 * Fire after initEvent
30011 * @param {Roo.bootstrap.DocumentViewer} this
30017 * @param {Roo.bootstrap.DocumentViewer} this
30022 * Fire after download button
30023 * @param {Roo.bootstrap.DocumentViewer} this
30028 * Fire after trash button
30029 * @param {Roo.bootstrap.DocumentViewer} this
30036 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
30038 showDownload : true,
30042 getAutoCreate : function()
30046 cls : 'roo-document-viewer',
30050 cls : 'roo-document-viewer-body',
30054 cls : 'roo-document-viewer-thumb',
30058 cls : 'roo-document-viewer-image'
30066 cls : 'roo-document-viewer-footer',
30069 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30073 cls : 'btn-group roo-document-viewer-download',
30077 cls : 'btn btn-default',
30078 html : '<i class="fa fa-download"></i>'
30084 cls : 'btn-group roo-document-viewer-trash',
30088 cls : 'btn btn-default',
30089 html : '<i class="fa fa-trash"></i>'
30102 initEvents : function()
30104 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30105 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30107 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30108 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30110 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30111 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30113 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30114 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30116 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30117 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30119 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30120 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30122 this.bodyEl.on('click', this.onClick, this);
30123 this.downloadBtn.on('click', this.onDownload, this);
30124 this.trashBtn.on('click', this.onTrash, this);
30126 this.downloadBtn.hide();
30127 this.trashBtn.hide();
30129 if(this.showDownload){
30130 this.downloadBtn.show();
30133 if(this.showTrash){
30134 this.trashBtn.show();
30137 if(!this.showDownload && !this.showTrash) {
30138 this.footerEl.hide();
30143 initial : function()
30145 this.fireEvent('initial', this);
30149 onClick : function(e)
30151 e.preventDefault();
30153 this.fireEvent('click', this);
30156 onDownload : function(e)
30158 e.preventDefault();
30160 this.fireEvent('download', this);
30163 onTrash : function(e)
30165 e.preventDefault();
30167 this.fireEvent('trash', this);
30179 * @class Roo.bootstrap.NavProgressBar
30180 * @extends Roo.bootstrap.Component
30181 * Bootstrap NavProgressBar class
30184 * Create a new nav progress bar
30185 * @param {Object} config The config object
30188 Roo.bootstrap.NavProgressBar = function(config){
30189 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30191 this.bullets = this.bullets || [];
30193 // Roo.bootstrap.NavProgressBar.register(this);
30197 * Fires when the active item changes
30198 * @param {Roo.bootstrap.NavProgressBar} this
30199 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30200 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30207 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30212 getAutoCreate : function()
30214 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30218 cls : 'roo-navigation-bar-group',
30222 cls : 'roo-navigation-top-bar'
30226 cls : 'roo-navigation-bullets-bar',
30230 cls : 'roo-navigation-bar'
30237 cls : 'roo-navigation-bottom-bar'
30247 initEvents: function()
30252 onRender : function(ct, position)
30254 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30256 if(this.bullets.length){
30257 Roo.each(this.bullets, function(b){
30266 addItem : function(cfg)
30268 var item = new Roo.bootstrap.NavProgressItem(cfg);
30270 item.parentId = this.id;
30271 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30274 var top = new Roo.bootstrap.Element({
30276 cls : 'roo-navigation-bar-text'
30279 var bottom = new Roo.bootstrap.Element({
30281 cls : 'roo-navigation-bar-text'
30284 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30285 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30287 var topText = new Roo.bootstrap.Element({
30289 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30292 var bottomText = new Roo.bootstrap.Element({
30294 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30297 topText.onRender(top.el, null);
30298 bottomText.onRender(bottom.el, null);
30301 item.bottomEl = bottom;
30304 this.barItems.push(item);
30309 getActive : function()
30311 var active = false;
30313 Roo.each(this.barItems, function(v){
30315 if (!v.isActive()) {
30327 setActiveItem : function(item)
30331 Roo.each(this.barItems, function(v){
30332 if (v.rid == item.rid) {
30336 if (v.isActive()) {
30337 v.setActive(false);
30342 item.setActive(true);
30344 this.fireEvent('changed', this, item, prev);
30347 getBarItem: function(rid)
30351 Roo.each(this.barItems, function(e) {
30352 if (e.rid != rid) {
30363 indexOfItem : function(item)
30367 Roo.each(this.barItems, function(v, i){
30369 if (v.rid != item.rid) {
30380 setActiveNext : function()
30382 var i = this.indexOfItem(this.getActive());
30384 if (i > this.barItems.length) {
30388 this.setActiveItem(this.barItems[i+1]);
30391 setActivePrev : function()
30393 var i = this.indexOfItem(this.getActive());
30399 this.setActiveItem(this.barItems[i-1]);
30402 format : function()
30404 if(!this.barItems.length){
30408 var width = 100 / this.barItems.length;
30410 Roo.each(this.barItems, function(i){
30411 i.el.setStyle('width', width + '%');
30412 i.topEl.el.setStyle('width', width + '%');
30413 i.bottomEl.el.setStyle('width', width + '%');
30422 * Nav Progress Item
30427 * @class Roo.bootstrap.NavProgressItem
30428 * @extends Roo.bootstrap.Component
30429 * Bootstrap NavProgressItem class
30430 * @cfg {String} rid the reference id
30431 * @cfg {Boolean} active (true|false) Is item active default false
30432 * @cfg {Boolean} disabled (true|false) Is item active default false
30433 * @cfg {String} html
30434 * @cfg {String} position (top|bottom) text position default bottom
30435 * @cfg {String} icon show icon instead of number
30438 * Create a new NavProgressItem
30439 * @param {Object} config The config object
30441 Roo.bootstrap.NavProgressItem = function(config){
30442 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30447 * The raw click event for the entire grid.
30448 * @param {Roo.bootstrap.NavProgressItem} this
30449 * @param {Roo.EventObject} e
30456 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30462 position : 'bottom',
30465 getAutoCreate : function()
30467 var iconCls = 'roo-navigation-bar-item-icon';
30469 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30473 cls: 'roo-navigation-bar-item',
30483 cfg.cls += ' active';
30486 cfg.cls += ' disabled';
30492 disable : function()
30494 this.setDisabled(true);
30497 enable : function()
30499 this.setDisabled(false);
30502 initEvents: function()
30504 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30506 this.iconEl.on('click', this.onClick, this);
30509 onClick : function(e)
30511 e.preventDefault();
30517 if(this.fireEvent('click', this, e) === false){
30521 this.parent().setActiveItem(this);
30524 isActive: function ()
30526 return this.active;
30529 setActive : function(state)
30531 if(this.active == state){
30535 this.active = state;
30538 this.el.addClass('active');
30542 this.el.removeClass('active');
30547 setDisabled : function(state)
30549 if(this.disabled == state){
30553 this.disabled = state;
30556 this.el.addClass('disabled');
30560 this.el.removeClass('disabled');
30563 tooltipEl : function()
30565 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30578 * @class Roo.bootstrap.FieldLabel
30579 * @extends Roo.bootstrap.Component
30580 * Bootstrap FieldLabel class
30581 * @cfg {String} html contents of the element
30582 * @cfg {String} tag tag of the element default label
30583 * @cfg {String} cls class of the element
30584 * @cfg {String} target label target
30585 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30586 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30587 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30588 * @cfg {String} iconTooltip default "This field is required"
30589 * @cfg {String} indicatorpos (left|right) default left
30592 * Create a new FieldLabel
30593 * @param {Object} config The config object
30596 Roo.bootstrap.FieldLabel = function(config){
30597 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30602 * Fires after the field has been marked as invalid.
30603 * @param {Roo.form.FieldLabel} this
30604 * @param {String} msg The validation message
30609 * Fires after the field has been validated with no errors.
30610 * @param {Roo.form.FieldLabel} this
30616 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30623 invalidClass : 'has-warning',
30624 validClass : 'has-success',
30625 iconTooltip : 'This field is required',
30626 indicatorpos : 'left',
30628 getAutoCreate : function(){
30631 if (!this.allowBlank) {
30637 cls : 'roo-bootstrap-field-label ' + this.cls,
30642 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30643 tooltip : this.iconTooltip
30652 if(this.indicatorpos == 'right'){
30655 cls : 'roo-bootstrap-field-label ' + this.cls,
30664 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30665 tooltip : this.iconTooltip
30674 initEvents: function()
30676 Roo.bootstrap.Element.superclass.initEvents.call(this);
30678 this.indicator = this.indicatorEl();
30680 if(this.indicator){
30681 this.indicator.removeClass('visible');
30682 this.indicator.addClass('invisible');
30685 Roo.bootstrap.FieldLabel.register(this);
30688 indicatorEl : function()
30690 var indicator = this.el.select('i.roo-required-indicator',true).first();
30701 * Mark this field as valid
30703 markValid : function()
30705 if(this.indicator){
30706 this.indicator.removeClass('visible');
30707 this.indicator.addClass('invisible');
30709 if (Roo.bootstrap.version == 3) {
30710 this.el.removeClass(this.invalidClass);
30711 this.el.addClass(this.validClass);
30713 this.el.removeClass('is-invalid');
30714 this.el.addClass('is-valid');
30718 this.fireEvent('valid', this);
30722 * Mark this field as invalid
30723 * @param {String} msg The validation message
30725 markInvalid : function(msg)
30727 if(this.indicator){
30728 this.indicator.removeClass('invisible');
30729 this.indicator.addClass('visible');
30731 if (Roo.bootstrap.version == 3) {
30732 this.el.removeClass(this.validClass);
30733 this.el.addClass(this.invalidClass);
30735 this.el.removeClass('is-valid');
30736 this.el.addClass('is-invalid');
30740 this.fireEvent('invalid', this, msg);
30746 Roo.apply(Roo.bootstrap.FieldLabel, {
30751 * register a FieldLabel Group
30752 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30754 register : function(label)
30756 if(this.groups.hasOwnProperty(label.target)){
30760 this.groups[label.target] = label;
30764 * fetch a FieldLabel Group based on the target
30765 * @param {string} target
30766 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30768 get: function(target) {
30769 if (typeof(this.groups[target]) == 'undefined') {
30773 return this.groups[target] ;
30782 * page DateSplitField.
30788 * @class Roo.bootstrap.DateSplitField
30789 * @extends Roo.bootstrap.Component
30790 * Bootstrap DateSplitField class
30791 * @cfg {string} fieldLabel - the label associated
30792 * @cfg {Number} labelWidth set the width of label (0-12)
30793 * @cfg {String} labelAlign (top|left)
30794 * @cfg {Boolean} dayAllowBlank (true|false) default false
30795 * @cfg {Boolean} monthAllowBlank (true|false) default false
30796 * @cfg {Boolean} yearAllowBlank (true|false) default false
30797 * @cfg {string} dayPlaceholder
30798 * @cfg {string} monthPlaceholder
30799 * @cfg {string} yearPlaceholder
30800 * @cfg {string} dayFormat default 'd'
30801 * @cfg {string} monthFormat default 'm'
30802 * @cfg {string} yearFormat default 'Y'
30803 * @cfg {Number} labellg set the width of label (1-12)
30804 * @cfg {Number} labelmd set the width of label (1-12)
30805 * @cfg {Number} labelsm set the width of label (1-12)
30806 * @cfg {Number} labelxs set the width of label (1-12)
30810 * Create a new DateSplitField
30811 * @param {Object} config The config object
30814 Roo.bootstrap.DateSplitField = function(config){
30815 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30821 * getting the data of years
30822 * @param {Roo.bootstrap.DateSplitField} this
30823 * @param {Object} years
30828 * getting the data of days
30829 * @param {Roo.bootstrap.DateSplitField} this
30830 * @param {Object} days
30835 * Fires after the field has been marked as invalid.
30836 * @param {Roo.form.Field} this
30837 * @param {String} msg The validation message
30842 * Fires after the field has been validated with no errors.
30843 * @param {Roo.form.Field} this
30849 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30852 labelAlign : 'top',
30854 dayAllowBlank : false,
30855 monthAllowBlank : false,
30856 yearAllowBlank : false,
30857 dayPlaceholder : '',
30858 monthPlaceholder : '',
30859 yearPlaceholder : '',
30863 isFormField : true,
30869 getAutoCreate : function()
30873 cls : 'row roo-date-split-field-group',
30878 cls : 'form-hidden-field roo-date-split-field-group-value',
30884 var labelCls = 'col-md-12';
30885 var contentCls = 'col-md-4';
30887 if(this.fieldLabel){
30891 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30895 html : this.fieldLabel
30900 if(this.labelAlign == 'left'){
30902 if(this.labelWidth > 12){
30903 label.style = "width: " + this.labelWidth + 'px';
30906 if(this.labelWidth < 13 && this.labelmd == 0){
30907 this.labelmd = this.labelWidth;
30910 if(this.labellg > 0){
30911 labelCls = ' col-lg-' + this.labellg;
30912 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30915 if(this.labelmd > 0){
30916 labelCls = ' col-md-' + this.labelmd;
30917 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30920 if(this.labelsm > 0){
30921 labelCls = ' col-sm-' + this.labelsm;
30922 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30925 if(this.labelxs > 0){
30926 labelCls = ' col-xs-' + this.labelxs;
30927 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30931 label.cls += ' ' + labelCls;
30933 cfg.cn.push(label);
30936 Roo.each(['day', 'month', 'year'], function(t){
30939 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30946 inputEl: function ()
30948 return this.el.select('.roo-date-split-field-group-value', true).first();
30951 onRender : function(ct, position)
30955 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30957 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30959 this.dayField = new Roo.bootstrap.ComboBox({
30960 allowBlank : this.dayAllowBlank,
30961 alwaysQuery : true,
30962 displayField : 'value',
30965 forceSelection : true,
30967 placeholder : this.dayPlaceholder,
30968 selectOnFocus : true,
30969 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30970 triggerAction : 'all',
30972 valueField : 'value',
30973 store : new Roo.data.SimpleStore({
30974 data : (function() {
30976 _this.fireEvent('days', _this, days);
30979 fields : [ 'value' ]
30982 select : function (_self, record, index)
30984 _this.setValue(_this.getValue());
30989 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30991 this.monthField = new Roo.bootstrap.MonthField({
30992 after : '<i class=\"fa fa-calendar\"></i>',
30993 allowBlank : this.monthAllowBlank,
30994 placeholder : this.monthPlaceholder,
30997 render : function (_self)
30999 this.el.select('span.input-group-addon', true).first().on('click', function(e){
31000 e.preventDefault();
31004 select : function (_self, oldvalue, newvalue)
31006 _this.setValue(_this.getValue());
31011 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
31013 this.yearField = new Roo.bootstrap.ComboBox({
31014 allowBlank : this.yearAllowBlank,
31015 alwaysQuery : true,
31016 displayField : 'value',
31019 forceSelection : true,
31021 placeholder : this.yearPlaceholder,
31022 selectOnFocus : true,
31023 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
31024 triggerAction : 'all',
31026 valueField : 'value',
31027 store : new Roo.data.SimpleStore({
31028 data : (function() {
31030 _this.fireEvent('years', _this, years);
31033 fields : [ 'value' ]
31036 select : function (_self, record, index)
31038 _this.setValue(_this.getValue());
31043 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
31046 setValue : function(v, format)
31048 this.inputEl.dom.value = v;
31050 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
31052 var d = Date.parseDate(v, f);
31059 this.setDay(d.format(this.dayFormat));
31060 this.setMonth(d.format(this.monthFormat));
31061 this.setYear(d.format(this.yearFormat));
31068 setDay : function(v)
31070 this.dayField.setValue(v);
31071 this.inputEl.dom.value = this.getValue();
31076 setMonth : function(v)
31078 this.monthField.setValue(v, true);
31079 this.inputEl.dom.value = this.getValue();
31084 setYear : function(v)
31086 this.yearField.setValue(v);
31087 this.inputEl.dom.value = this.getValue();
31092 getDay : function()
31094 return this.dayField.getValue();
31097 getMonth : function()
31099 return this.monthField.getValue();
31102 getYear : function()
31104 return this.yearField.getValue();
31107 getValue : function()
31109 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31111 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31121 this.inputEl.dom.value = '';
31126 validate : function()
31128 var d = this.dayField.validate();
31129 var m = this.monthField.validate();
31130 var y = this.yearField.validate();
31135 (!this.dayAllowBlank && !d) ||
31136 (!this.monthAllowBlank && !m) ||
31137 (!this.yearAllowBlank && !y)
31142 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31151 this.markInvalid();
31156 markValid : function()
31159 var label = this.el.select('label', true).first();
31160 var icon = this.el.select('i.fa-star', true).first();
31166 this.fireEvent('valid', this);
31170 * Mark this field as invalid
31171 * @param {String} msg The validation message
31173 markInvalid : function(msg)
31176 var label = this.el.select('label', true).first();
31177 var icon = this.el.select('i.fa-star', true).first();
31179 if(label && !icon){
31180 this.el.select('.roo-date-split-field-label', true).createChild({
31182 cls : 'text-danger fa fa-lg fa-star',
31183 tooltip : 'This field is required',
31184 style : 'margin-right:5px;'
31188 this.fireEvent('invalid', this, msg);
31191 clearInvalid : function()
31193 var label = this.el.select('label', true).first();
31194 var icon = this.el.select('i.fa-star', true).first();
31200 this.fireEvent('valid', this);
31203 getName: function()
31213 * http://masonry.desandro.com
31215 * The idea is to render all the bricks based on vertical width...
31217 * The original code extends 'outlayer' - we might need to use that....
31223 * @class Roo.bootstrap.LayoutMasonry
31224 * @extends Roo.bootstrap.Component
31225 * Bootstrap Layout Masonry class
31228 * Create a new Element
31229 * @param {Object} config The config object
31232 Roo.bootstrap.LayoutMasonry = function(config){
31234 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31238 Roo.bootstrap.LayoutMasonry.register(this);
31244 * Fire after layout the items
31245 * @param {Roo.bootstrap.LayoutMasonry} this
31246 * @param {Roo.EventObject} e
31253 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31256 * @cfg {Boolean} isLayoutInstant = no animation?
31258 isLayoutInstant : false, // needed?
31261 * @cfg {Number} boxWidth width of the columns
31266 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31271 * @cfg {Number} padWidth padding below box..
31276 * @cfg {Number} gutter gutter width..
31281 * @cfg {Number} maxCols maximum number of columns
31287 * @cfg {Boolean} isAutoInitial defalut true
31289 isAutoInitial : true,
31294 * @cfg {Boolean} isHorizontal defalut false
31296 isHorizontal : false,
31298 currentSize : null,
31304 bricks: null, //CompositeElement
31308 _isLayoutInited : false,
31310 // isAlternative : false, // only use for vertical layout...
31313 * @cfg {Number} alternativePadWidth padding below box..
31315 alternativePadWidth : 50,
31317 selectedBrick : [],
31319 getAutoCreate : function(){
31321 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31325 cls: 'blog-masonary-wrapper ' + this.cls,
31327 cls : 'mas-boxes masonary'
31334 getChildContainer: function( )
31336 if (this.boxesEl) {
31337 return this.boxesEl;
31340 this.boxesEl = this.el.select('.mas-boxes').first();
31342 return this.boxesEl;
31346 initEvents : function()
31350 if(this.isAutoInitial){
31351 Roo.log('hook children rendered');
31352 this.on('childrenrendered', function() {
31353 Roo.log('children rendered');
31359 initial : function()
31361 this.selectedBrick = [];
31363 this.currentSize = this.el.getBox(true);
31365 Roo.EventManager.onWindowResize(this.resize, this);
31367 if(!this.isAutoInitial){
31375 //this.layout.defer(500,this);
31379 resize : function()
31381 var cs = this.el.getBox(true);
31384 this.currentSize.width == cs.width &&
31385 this.currentSize.x == cs.x &&
31386 this.currentSize.height == cs.height &&
31387 this.currentSize.y == cs.y
31389 Roo.log("no change in with or X or Y");
31393 this.currentSize = cs;
31399 layout : function()
31401 this._resetLayout();
31403 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31405 this.layoutItems( isInstant );
31407 this._isLayoutInited = true;
31409 this.fireEvent('layout', this);
31413 _resetLayout : function()
31415 if(this.isHorizontal){
31416 this.horizontalMeasureColumns();
31420 this.verticalMeasureColumns();
31424 verticalMeasureColumns : function()
31426 this.getContainerWidth();
31428 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31429 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31433 var boxWidth = this.boxWidth + this.padWidth;
31435 if(this.containerWidth < this.boxWidth){
31436 boxWidth = this.containerWidth
31439 var containerWidth = this.containerWidth;
31441 var cols = Math.floor(containerWidth / boxWidth);
31443 this.cols = Math.max( cols, 1 );
31445 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31447 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31449 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31451 this.colWidth = boxWidth + avail - this.padWidth;
31453 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31454 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31457 horizontalMeasureColumns : function()
31459 this.getContainerWidth();
31461 var boxWidth = this.boxWidth;
31463 if(this.containerWidth < boxWidth){
31464 boxWidth = this.containerWidth;
31467 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31469 this.el.setHeight(boxWidth);
31473 getContainerWidth : function()
31475 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31478 layoutItems : function( isInstant )
31480 Roo.log(this.bricks);
31482 var items = Roo.apply([], this.bricks);
31484 if(this.isHorizontal){
31485 this._horizontalLayoutItems( items , isInstant );
31489 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31490 // this._verticalAlternativeLayoutItems( items , isInstant );
31494 this._verticalLayoutItems( items , isInstant );
31498 _verticalLayoutItems : function ( items , isInstant)
31500 if ( !items || !items.length ) {
31505 ['xs', 'xs', 'xs', 'tall'],
31506 ['xs', 'xs', 'tall'],
31507 ['xs', 'xs', 'sm'],
31508 ['xs', 'xs', 'xs'],
31514 ['sm', 'xs', 'xs'],
31518 ['tall', 'xs', 'xs', 'xs'],
31519 ['tall', 'xs', 'xs'],
31531 Roo.each(items, function(item, k){
31533 switch (item.size) {
31534 // these layouts take up a full box,
31545 boxes.push([item]);
31568 var filterPattern = function(box, length)
31576 var pattern = box.slice(0, length);
31580 Roo.each(pattern, function(i){
31581 format.push(i.size);
31584 Roo.each(standard, function(s){
31586 if(String(s) != String(format)){
31595 if(!match && length == 1){
31600 filterPattern(box, length - 1);
31604 queue.push(pattern);
31606 box = box.slice(length, box.length);
31608 filterPattern(box, 4);
31614 Roo.each(boxes, function(box, k){
31620 if(box.length == 1){
31625 filterPattern(box, 4);
31629 this._processVerticalLayoutQueue( queue, isInstant );
31633 // _verticalAlternativeLayoutItems : function( items , isInstant )
31635 // if ( !items || !items.length ) {
31639 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31643 _horizontalLayoutItems : function ( items , isInstant)
31645 if ( !items || !items.length || items.length < 3) {
31651 var eItems = items.slice(0, 3);
31653 items = items.slice(3, items.length);
31656 ['xs', 'xs', 'xs', 'wide'],
31657 ['xs', 'xs', 'wide'],
31658 ['xs', 'xs', 'sm'],
31659 ['xs', 'xs', 'xs'],
31665 ['sm', 'xs', 'xs'],
31669 ['wide', 'xs', 'xs', 'xs'],
31670 ['wide', 'xs', 'xs'],
31683 Roo.each(items, function(item, k){
31685 switch (item.size) {
31696 boxes.push([item]);
31720 var filterPattern = function(box, length)
31728 var pattern = box.slice(0, length);
31732 Roo.each(pattern, function(i){
31733 format.push(i.size);
31736 Roo.each(standard, function(s){
31738 if(String(s) != String(format)){
31747 if(!match && length == 1){
31752 filterPattern(box, length - 1);
31756 queue.push(pattern);
31758 box = box.slice(length, box.length);
31760 filterPattern(box, 4);
31766 Roo.each(boxes, function(box, k){
31772 if(box.length == 1){
31777 filterPattern(box, 4);
31784 var pos = this.el.getBox(true);
31788 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31790 var hit_end = false;
31792 Roo.each(queue, function(box){
31796 Roo.each(box, function(b){
31798 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31808 Roo.each(box, function(b){
31810 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31813 mx = Math.max(mx, b.x);
31817 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31821 Roo.each(box, function(b){
31823 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31837 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31840 /** Sets position of item in DOM
31841 * @param {Element} item
31842 * @param {Number} x - horizontal position
31843 * @param {Number} y - vertical position
31844 * @param {Boolean} isInstant - disables transitions
31846 _processVerticalLayoutQueue : function( queue, isInstant )
31848 var pos = this.el.getBox(true);
31853 for (var i = 0; i < this.cols; i++){
31857 Roo.each(queue, function(box, k){
31859 var col = k % this.cols;
31861 Roo.each(box, function(b,kk){
31863 b.el.position('absolute');
31865 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31866 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31868 if(b.size == 'md-left' || b.size == 'md-right'){
31869 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31870 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31873 b.el.setWidth(width);
31874 b.el.setHeight(height);
31876 b.el.select('iframe',true).setSize(width,height);
31880 for (var i = 0; i < this.cols; i++){
31882 if(maxY[i] < maxY[col]){
31887 col = Math.min(col, i);
31891 x = pos.x + col * (this.colWidth + this.padWidth);
31895 var positions = [];
31897 switch (box.length){
31899 positions = this.getVerticalOneBoxColPositions(x, y, box);
31902 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31905 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31908 positions = this.getVerticalFourBoxColPositions(x, y, box);
31914 Roo.each(box, function(b,kk){
31916 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31918 var sz = b.el.getSize();
31920 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31928 for (var i = 0; i < this.cols; i++){
31929 mY = Math.max(mY, maxY[i]);
31932 this.el.setHeight(mY - pos.y);
31936 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31938 // var pos = this.el.getBox(true);
31941 // var maxX = pos.right;
31943 // var maxHeight = 0;
31945 // Roo.each(items, function(item, k){
31949 // item.el.position('absolute');
31951 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31953 // item.el.setWidth(width);
31955 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31957 // item.el.setHeight(height);
31960 // item.el.setXY([x, y], isInstant ? false : true);
31962 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31965 // y = y + height + this.alternativePadWidth;
31967 // maxHeight = maxHeight + height + this.alternativePadWidth;
31971 // this.el.setHeight(maxHeight);
31975 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31977 var pos = this.el.getBox(true);
31982 var maxX = pos.right;
31984 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31986 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31988 Roo.each(queue, function(box, k){
31990 Roo.each(box, function(b, kk){
31992 b.el.position('absolute');
31994 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31995 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31997 if(b.size == 'md-left' || b.size == 'md-right'){
31998 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31999 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32002 b.el.setWidth(width);
32003 b.el.setHeight(height);
32011 var positions = [];
32013 switch (box.length){
32015 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
32018 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
32021 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
32024 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
32030 Roo.each(box, function(b,kk){
32032 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
32034 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
32042 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
32044 Roo.each(eItems, function(b,k){
32046 b.size = (k == 0) ? 'sm' : 'xs';
32047 b.x = (k == 0) ? 2 : 1;
32048 b.y = (k == 0) ? 2 : 1;
32050 b.el.position('absolute');
32052 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32054 b.el.setWidth(width);
32056 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32058 b.el.setHeight(height);
32062 var positions = [];
32065 x : maxX - this.unitWidth * 2 - this.gutter,
32070 x : maxX - this.unitWidth,
32071 y : minY + (this.unitWidth + this.gutter) * 2
32075 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32079 Roo.each(eItems, function(b,k){
32081 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32087 getVerticalOneBoxColPositions : function(x, y, box)
32091 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32093 if(box[0].size == 'md-left'){
32097 if(box[0].size == 'md-right'){
32102 x : x + (this.unitWidth + this.gutter) * rand,
32109 getVerticalTwoBoxColPositions : function(x, y, box)
32113 if(box[0].size == 'xs'){
32117 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32121 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32135 x : x + (this.unitWidth + this.gutter) * 2,
32136 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32143 getVerticalThreeBoxColPositions : function(x, y, box)
32147 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32155 x : x + (this.unitWidth + this.gutter) * 1,
32160 x : x + (this.unitWidth + this.gutter) * 2,
32168 if(box[0].size == 'xs' && box[1].size == 'xs'){
32177 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32181 x : x + (this.unitWidth + this.gutter) * 1,
32195 x : x + (this.unitWidth + this.gutter) * 2,
32200 x : x + (this.unitWidth + this.gutter) * 2,
32201 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32208 getVerticalFourBoxColPositions : function(x, y, box)
32212 if(box[0].size == 'xs'){
32221 y : y + (this.unitHeight + this.gutter) * 1
32226 y : y + (this.unitHeight + this.gutter) * 2
32230 x : x + (this.unitWidth + this.gutter) * 1,
32244 x : x + (this.unitWidth + this.gutter) * 2,
32249 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32250 y : y + (this.unitHeight + this.gutter) * 1
32254 x : x + (this.unitWidth + this.gutter) * 2,
32255 y : y + (this.unitWidth + this.gutter) * 2
32262 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32266 if(box[0].size == 'md-left'){
32268 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32275 if(box[0].size == 'md-right'){
32277 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32278 y : minY + (this.unitWidth + this.gutter) * 1
32284 var rand = Math.floor(Math.random() * (4 - box[0].y));
32287 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32288 y : minY + (this.unitWidth + this.gutter) * rand
32295 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32299 if(box[0].size == 'xs'){
32302 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32307 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32308 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32316 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32321 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32322 y : minY + (this.unitWidth + this.gutter) * 2
32329 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32333 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32336 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32341 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32342 y : minY + (this.unitWidth + this.gutter) * 1
32346 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32347 y : minY + (this.unitWidth + this.gutter) * 2
32354 if(box[0].size == 'xs' && box[1].size == 'xs'){
32357 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32362 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32367 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32368 y : minY + (this.unitWidth + this.gutter) * 1
32376 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32381 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32382 y : minY + (this.unitWidth + this.gutter) * 2
32386 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32387 y : minY + (this.unitWidth + this.gutter) * 2
32394 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32398 if(box[0].size == 'xs'){
32401 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32406 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32411 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),
32416 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32417 y : minY + (this.unitWidth + this.gutter) * 1
32425 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32430 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32431 y : minY + (this.unitWidth + this.gutter) * 2
32435 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32436 y : minY + (this.unitWidth + this.gutter) * 2
32440 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),
32441 y : minY + (this.unitWidth + this.gutter) * 2
32449 * remove a Masonry Brick
32450 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32452 removeBrick : function(brick_id)
32458 for (var i = 0; i<this.bricks.length; i++) {
32459 if (this.bricks[i].id == brick_id) {
32460 this.bricks.splice(i,1);
32461 this.el.dom.removeChild(Roo.get(brick_id).dom);
32468 * adds a Masonry Brick
32469 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32471 addBrick : function(cfg)
32473 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32474 //this.register(cn);
32475 cn.parentId = this.id;
32476 cn.render(this.el);
32481 * register a Masonry Brick
32482 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32485 register : function(brick)
32487 this.bricks.push(brick);
32488 brick.masonryId = this.id;
32492 * clear all the Masonry Brick
32494 clearAll : function()
32497 //this.getChildContainer().dom.innerHTML = "";
32498 this.el.dom.innerHTML = '';
32501 getSelected : function()
32503 if (!this.selectedBrick) {
32507 return this.selectedBrick;
32511 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32515 * register a Masonry Layout
32516 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32519 register : function(layout)
32521 this.groups[layout.id] = layout;
32524 * fetch a Masonry Layout based on the masonry layout ID
32525 * @param {string} the masonry layout to add
32526 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32529 get: function(layout_id) {
32530 if (typeof(this.groups[layout_id]) == 'undefined') {
32533 return this.groups[layout_id] ;
32545 * http://masonry.desandro.com
32547 * The idea is to render all the bricks based on vertical width...
32549 * The original code extends 'outlayer' - we might need to use that....
32555 * @class Roo.bootstrap.LayoutMasonryAuto
32556 * @extends Roo.bootstrap.Component
32557 * Bootstrap Layout Masonry class
32560 * Create a new Element
32561 * @param {Object} config The config object
32564 Roo.bootstrap.LayoutMasonryAuto = function(config){
32565 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32568 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32571 * @cfg {Boolean} isFitWidth - resize the width..
32573 isFitWidth : false, // options..
32575 * @cfg {Boolean} isOriginLeft = left align?
32577 isOriginLeft : true,
32579 * @cfg {Boolean} isOriginTop = top align?
32581 isOriginTop : false,
32583 * @cfg {Boolean} isLayoutInstant = no animation?
32585 isLayoutInstant : false, // needed?
32587 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32589 isResizingContainer : true,
32591 * @cfg {Number} columnWidth width of the columns
32597 * @cfg {Number} maxCols maximum number of columns
32602 * @cfg {Number} padHeight padding below box..
32608 * @cfg {Boolean} isAutoInitial defalut true
32611 isAutoInitial : true,
32617 initialColumnWidth : 0,
32618 currentSize : null,
32620 colYs : null, // array.
32627 bricks: null, //CompositeElement
32628 cols : 0, // array?
32629 // element : null, // wrapped now this.el
32630 _isLayoutInited : null,
32633 getAutoCreate : function(){
32637 cls: 'blog-masonary-wrapper ' + this.cls,
32639 cls : 'mas-boxes masonary'
32646 getChildContainer: function( )
32648 if (this.boxesEl) {
32649 return this.boxesEl;
32652 this.boxesEl = this.el.select('.mas-boxes').first();
32654 return this.boxesEl;
32658 initEvents : function()
32662 if(this.isAutoInitial){
32663 Roo.log('hook children rendered');
32664 this.on('childrenrendered', function() {
32665 Roo.log('children rendered');
32672 initial : function()
32674 this.reloadItems();
32676 this.currentSize = this.el.getBox(true);
32678 /// was window resize... - let's see if this works..
32679 Roo.EventManager.onWindowResize(this.resize, this);
32681 if(!this.isAutoInitial){
32686 this.layout.defer(500,this);
32689 reloadItems: function()
32691 this.bricks = this.el.select('.masonry-brick', true);
32693 this.bricks.each(function(b) {
32694 //Roo.log(b.getSize());
32695 if (!b.attr('originalwidth')) {
32696 b.attr('originalwidth', b.getSize().width);
32701 Roo.log(this.bricks.elements.length);
32704 resize : function()
32707 var cs = this.el.getBox(true);
32709 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32710 Roo.log("no change in with or X");
32713 this.currentSize = cs;
32717 layout : function()
32720 this._resetLayout();
32721 //this._manageStamps();
32723 // don't animate first layout
32724 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32725 this.layoutItems( isInstant );
32727 // flag for initalized
32728 this._isLayoutInited = true;
32731 layoutItems : function( isInstant )
32733 //var items = this._getItemsForLayout( this.items );
32734 // original code supports filtering layout items.. we just ignore it..
32736 this._layoutItems( this.bricks , isInstant );
32738 this._postLayout();
32740 _layoutItems : function ( items , isInstant)
32742 //this.fireEvent( 'layout', this, items );
32745 if ( !items || !items.elements.length ) {
32746 // no items, emit event with empty array
32751 items.each(function(item) {
32752 Roo.log("layout item");
32754 // get x/y object from method
32755 var position = this._getItemLayoutPosition( item );
32757 position.item = item;
32758 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32759 queue.push( position );
32762 this._processLayoutQueue( queue );
32764 /** Sets position of item in DOM
32765 * @param {Element} item
32766 * @param {Number} x - horizontal position
32767 * @param {Number} y - vertical position
32768 * @param {Boolean} isInstant - disables transitions
32770 _processLayoutQueue : function( queue )
32772 for ( var i=0, len = queue.length; i < len; i++ ) {
32773 var obj = queue[i];
32774 obj.item.position('absolute');
32775 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32781 * Any logic you want to do after each layout,
32782 * i.e. size the container
32784 _postLayout : function()
32786 this.resizeContainer();
32789 resizeContainer : function()
32791 if ( !this.isResizingContainer ) {
32794 var size = this._getContainerSize();
32796 this.el.setSize(size.width,size.height);
32797 this.boxesEl.setSize(size.width,size.height);
32803 _resetLayout : function()
32805 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32806 this.colWidth = this.el.getWidth();
32807 //this.gutter = this.el.getWidth();
32809 this.measureColumns();
32815 this.colYs.push( 0 );
32821 measureColumns : function()
32823 this.getContainerWidth();
32824 // if columnWidth is 0, default to outerWidth of first item
32825 if ( !this.columnWidth ) {
32826 var firstItem = this.bricks.first();
32827 Roo.log(firstItem);
32828 this.columnWidth = this.containerWidth;
32829 if (firstItem && firstItem.attr('originalwidth') ) {
32830 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32832 // columnWidth fall back to item of first element
32833 Roo.log("set column width?");
32834 this.initialColumnWidth = this.columnWidth ;
32836 // if first elem has no width, default to size of container
32841 if (this.initialColumnWidth) {
32842 this.columnWidth = this.initialColumnWidth;
32847 // column width is fixed at the top - however if container width get's smaller we should
32850 // this bit calcs how man columns..
32852 var columnWidth = this.columnWidth += this.gutter;
32854 // calculate columns
32855 var containerWidth = this.containerWidth + this.gutter;
32857 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32858 // fix rounding errors, typically with gutters
32859 var excess = columnWidth - containerWidth % columnWidth;
32862 // if overshoot is less than a pixel, round up, otherwise floor it
32863 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32864 cols = Math[ mathMethod ]( cols );
32865 this.cols = Math.max( cols, 1 );
32866 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32868 // padding positioning..
32869 var totalColWidth = this.cols * this.columnWidth;
32870 var padavail = this.containerWidth - totalColWidth;
32871 // so for 2 columns - we need 3 'pads'
32873 var padNeeded = (1+this.cols) * this.padWidth;
32875 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32877 this.columnWidth += padExtra
32878 //this.padWidth = Math.floor(padavail / ( this.cols));
32880 // adjust colum width so that padding is fixed??
32882 // we have 3 columns ... total = width * 3
32883 // we have X left over... that should be used by
32885 //if (this.expandC) {
32893 getContainerWidth : function()
32895 /* // container is parent if fit width
32896 var container = this.isFitWidth ? this.element.parentNode : this.element;
32897 // check that this.size and size are there
32898 // IE8 triggers resize on body size change, so they might not be
32900 var size = getSize( container ); //FIXME
32901 this.containerWidth = size && size.innerWidth; //FIXME
32904 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32908 _getItemLayoutPosition : function( item ) // what is item?
32910 // we resize the item to our columnWidth..
32912 item.setWidth(this.columnWidth);
32913 item.autoBoxAdjust = false;
32915 var sz = item.getSize();
32917 // how many columns does this brick span
32918 var remainder = this.containerWidth % this.columnWidth;
32920 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32921 // round if off by 1 pixel, otherwise use ceil
32922 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32923 colSpan = Math.min( colSpan, this.cols );
32925 // normally this should be '1' as we dont' currently allow multi width columns..
32927 var colGroup = this._getColGroup( colSpan );
32928 // get the minimum Y value from the columns
32929 var minimumY = Math.min.apply( Math, colGroup );
32930 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32932 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32934 // position the brick
32936 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32937 y: this.currentSize.y + minimumY + this.padHeight
32941 // apply setHeight to necessary columns
32942 var setHeight = minimumY + sz.height + this.padHeight;
32943 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32945 var setSpan = this.cols + 1 - colGroup.length;
32946 for ( var i = 0; i < setSpan; i++ ) {
32947 this.colYs[ shortColIndex + i ] = setHeight ;
32954 * @param {Number} colSpan - number of columns the element spans
32955 * @returns {Array} colGroup
32957 _getColGroup : function( colSpan )
32959 if ( colSpan < 2 ) {
32960 // if brick spans only one column, use all the column Ys
32965 // how many different places could this brick fit horizontally
32966 var groupCount = this.cols + 1 - colSpan;
32967 // for each group potential horizontal position
32968 for ( var i = 0; i < groupCount; i++ ) {
32969 // make an array of colY values for that one group
32970 var groupColYs = this.colYs.slice( i, i + colSpan );
32971 // and get the max value of the array
32972 colGroup[i] = Math.max.apply( Math, groupColYs );
32977 _manageStamp : function( stamp )
32979 var stampSize = stamp.getSize();
32980 var offset = stamp.getBox();
32981 // get the columns that this stamp affects
32982 var firstX = this.isOriginLeft ? offset.x : offset.right;
32983 var lastX = firstX + stampSize.width;
32984 var firstCol = Math.floor( firstX / this.columnWidth );
32985 firstCol = Math.max( 0, firstCol );
32987 var lastCol = Math.floor( lastX / this.columnWidth );
32988 // lastCol should not go over if multiple of columnWidth #425
32989 lastCol -= lastX % this.columnWidth ? 0 : 1;
32990 lastCol = Math.min( this.cols - 1, lastCol );
32992 // set colYs to bottom of the stamp
32993 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32996 for ( var i = firstCol; i <= lastCol; i++ ) {
32997 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
33002 _getContainerSize : function()
33004 this.maxY = Math.max.apply( Math, this.colYs );
33009 if ( this.isFitWidth ) {
33010 size.width = this._getContainerFitWidth();
33016 _getContainerFitWidth : function()
33018 var unusedCols = 0;
33019 // count unused columns
33022 if ( this.colYs[i] !== 0 ) {
33027 // fit container to columns that have been used
33028 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
33031 needsResizeLayout : function()
33033 var previousWidth = this.containerWidth;
33034 this.getContainerWidth();
33035 return previousWidth !== this.containerWidth;
33050 * @class Roo.bootstrap.MasonryBrick
33051 * @extends Roo.bootstrap.Component
33052 * Bootstrap MasonryBrick class
33055 * Create a new MasonryBrick
33056 * @param {Object} config The config object
33059 Roo.bootstrap.MasonryBrick = function(config){
33061 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
33063 Roo.bootstrap.MasonryBrick.register(this);
33069 * When a MasonryBrick is clcik
33070 * @param {Roo.bootstrap.MasonryBrick} this
33071 * @param {Roo.EventObject} e
33077 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33080 * @cfg {String} title
33084 * @cfg {String} html
33088 * @cfg {String} bgimage
33092 * @cfg {String} videourl
33096 * @cfg {String} cls
33100 * @cfg {String} href
33104 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33109 * @cfg {String} placetitle (center|bottom)
33114 * @cfg {Boolean} isFitContainer defalut true
33116 isFitContainer : true,
33119 * @cfg {Boolean} preventDefault defalut false
33121 preventDefault : false,
33124 * @cfg {Boolean} inverse defalut false
33126 maskInverse : false,
33128 getAutoCreate : function()
33130 if(!this.isFitContainer){
33131 return this.getSplitAutoCreate();
33134 var cls = 'masonry-brick masonry-brick-full';
33136 if(this.href.length){
33137 cls += ' masonry-brick-link';
33140 if(this.bgimage.length){
33141 cls += ' masonry-brick-image';
33144 if(this.maskInverse){
33145 cls += ' mask-inverse';
33148 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33149 cls += ' enable-mask';
33153 cls += ' masonry-' + this.size + '-brick';
33156 if(this.placetitle.length){
33158 switch (this.placetitle) {
33160 cls += ' masonry-center-title';
33163 cls += ' masonry-bottom-title';
33170 if(!this.html.length && !this.bgimage.length){
33171 cls += ' masonry-center-title';
33174 if(!this.html.length && this.bgimage.length){
33175 cls += ' masonry-bottom-title';
33180 cls += ' ' + this.cls;
33184 tag: (this.href.length) ? 'a' : 'div',
33189 cls: 'masonry-brick-mask'
33193 cls: 'masonry-brick-paragraph',
33199 if(this.href.length){
33200 cfg.href = this.href;
33203 var cn = cfg.cn[1].cn;
33205 if(this.title.length){
33208 cls: 'masonry-brick-title',
33213 if(this.html.length){
33216 cls: 'masonry-brick-text',
33221 if (!this.title.length && !this.html.length) {
33222 cfg.cn[1].cls += ' hide';
33225 if(this.bgimage.length){
33228 cls: 'masonry-brick-image-view',
33233 if(this.videourl.length){
33234 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33235 // youtube support only?
33238 cls: 'masonry-brick-image-view',
33241 allowfullscreen : true
33249 getSplitAutoCreate : function()
33251 var cls = 'masonry-brick masonry-brick-split';
33253 if(this.href.length){
33254 cls += ' masonry-brick-link';
33257 if(this.bgimage.length){
33258 cls += ' masonry-brick-image';
33262 cls += ' masonry-' + this.size + '-brick';
33265 switch (this.placetitle) {
33267 cls += ' masonry-center-title';
33270 cls += ' masonry-bottom-title';
33273 if(!this.bgimage.length){
33274 cls += ' masonry-center-title';
33277 if(this.bgimage.length){
33278 cls += ' masonry-bottom-title';
33284 cls += ' ' + this.cls;
33288 tag: (this.href.length) ? 'a' : 'div',
33293 cls: 'masonry-brick-split-head',
33297 cls: 'masonry-brick-paragraph',
33304 cls: 'masonry-brick-split-body',
33310 if(this.href.length){
33311 cfg.href = this.href;
33314 if(this.title.length){
33315 cfg.cn[0].cn[0].cn.push({
33317 cls: 'masonry-brick-title',
33322 if(this.html.length){
33323 cfg.cn[1].cn.push({
33325 cls: 'masonry-brick-text',
33330 if(this.bgimage.length){
33331 cfg.cn[0].cn.push({
33333 cls: 'masonry-brick-image-view',
33338 if(this.videourl.length){
33339 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33340 // youtube support only?
33341 cfg.cn[0].cn.cn.push({
33343 cls: 'masonry-brick-image-view',
33346 allowfullscreen : true
33353 initEvents: function()
33355 switch (this.size) {
33388 this.el.on('touchstart', this.onTouchStart, this);
33389 this.el.on('touchmove', this.onTouchMove, this);
33390 this.el.on('touchend', this.onTouchEnd, this);
33391 this.el.on('contextmenu', this.onContextMenu, this);
33393 this.el.on('mouseenter' ,this.enter, this);
33394 this.el.on('mouseleave', this.leave, this);
33395 this.el.on('click', this.onClick, this);
33398 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33399 this.parent().bricks.push(this);
33404 onClick: function(e, el)
33406 var time = this.endTimer - this.startTimer;
33407 // Roo.log(e.preventDefault());
33410 e.preventDefault();
33415 if(!this.preventDefault){
33419 e.preventDefault();
33421 if (this.activeClass != '') {
33422 this.selectBrick();
33425 this.fireEvent('click', this, e);
33428 enter: function(e, el)
33430 e.preventDefault();
33432 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33436 if(this.bgimage.length && this.html.length){
33437 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33441 leave: function(e, el)
33443 e.preventDefault();
33445 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33449 if(this.bgimage.length && this.html.length){
33450 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33454 onTouchStart: function(e, el)
33456 // e.preventDefault();
33458 this.touchmoved = false;
33460 if(!this.isFitContainer){
33464 if(!this.bgimage.length || !this.html.length){
33468 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33470 this.timer = new Date().getTime();
33474 onTouchMove: function(e, el)
33476 this.touchmoved = true;
33479 onContextMenu : function(e,el)
33481 e.preventDefault();
33482 e.stopPropagation();
33486 onTouchEnd: function(e, el)
33488 // e.preventDefault();
33490 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33497 if(!this.bgimage.length || !this.html.length){
33499 if(this.href.length){
33500 window.location.href = this.href;
33506 if(!this.isFitContainer){
33510 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33512 window.location.href = this.href;
33515 //selection on single brick only
33516 selectBrick : function() {
33518 if (!this.parentId) {
33522 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33523 var index = m.selectedBrick.indexOf(this.id);
33526 m.selectedBrick.splice(index,1);
33527 this.el.removeClass(this.activeClass);
33531 for(var i = 0; i < m.selectedBrick.length; i++) {
33532 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33533 b.el.removeClass(b.activeClass);
33536 m.selectedBrick = [];
33538 m.selectedBrick.push(this.id);
33539 this.el.addClass(this.activeClass);
33543 isSelected : function(){
33544 return this.el.hasClass(this.activeClass);
33549 Roo.apply(Roo.bootstrap.MasonryBrick, {
33552 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33554 * register a Masonry Brick
33555 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33558 register : function(brick)
33560 //this.groups[brick.id] = brick;
33561 this.groups.add(brick.id, brick);
33564 * fetch a masonry brick based on the masonry brick ID
33565 * @param {string} the masonry brick to add
33566 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33569 get: function(brick_id)
33571 // if (typeof(this.groups[brick_id]) == 'undefined') {
33574 // return this.groups[brick_id] ;
33576 if(this.groups.key(brick_id)) {
33577 return this.groups.key(brick_id);
33595 * @class Roo.bootstrap.Brick
33596 * @extends Roo.bootstrap.Component
33597 * Bootstrap Brick class
33600 * Create a new Brick
33601 * @param {Object} config The config object
33604 Roo.bootstrap.Brick = function(config){
33605 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33611 * When a Brick is click
33612 * @param {Roo.bootstrap.Brick} this
33613 * @param {Roo.EventObject} e
33619 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33622 * @cfg {String} title
33626 * @cfg {String} html
33630 * @cfg {String} bgimage
33634 * @cfg {String} cls
33638 * @cfg {String} href
33642 * @cfg {String} video
33646 * @cfg {Boolean} square
33650 getAutoCreate : function()
33652 var cls = 'roo-brick';
33654 if(this.href.length){
33655 cls += ' roo-brick-link';
33658 if(this.bgimage.length){
33659 cls += ' roo-brick-image';
33662 if(!this.html.length && !this.bgimage.length){
33663 cls += ' roo-brick-center-title';
33666 if(!this.html.length && this.bgimage.length){
33667 cls += ' roo-brick-bottom-title';
33671 cls += ' ' + this.cls;
33675 tag: (this.href.length) ? 'a' : 'div',
33680 cls: 'roo-brick-paragraph',
33686 if(this.href.length){
33687 cfg.href = this.href;
33690 var cn = cfg.cn[0].cn;
33692 if(this.title.length){
33695 cls: 'roo-brick-title',
33700 if(this.html.length){
33703 cls: 'roo-brick-text',
33710 if(this.bgimage.length){
33713 cls: 'roo-brick-image-view',
33721 initEvents: function()
33723 if(this.title.length || this.html.length){
33724 this.el.on('mouseenter' ,this.enter, this);
33725 this.el.on('mouseleave', this.leave, this);
33728 Roo.EventManager.onWindowResize(this.resize, this);
33730 if(this.bgimage.length){
33731 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33732 this.imageEl.on('load', this.onImageLoad, this);
33739 onImageLoad : function()
33744 resize : function()
33746 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33748 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33750 if(this.bgimage.length){
33751 var image = this.el.select('.roo-brick-image-view', true).first();
33753 image.setWidth(paragraph.getWidth());
33756 image.setHeight(paragraph.getWidth());
33759 this.el.setHeight(image.getHeight());
33760 paragraph.setHeight(image.getHeight());
33766 enter: function(e, el)
33768 e.preventDefault();
33770 if(this.bgimage.length){
33771 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33772 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33776 leave: function(e, el)
33778 e.preventDefault();
33780 if(this.bgimage.length){
33781 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33782 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33797 * @class Roo.bootstrap.NumberField
33798 * @extends Roo.bootstrap.Input
33799 * Bootstrap NumberField class
33805 * Create a new NumberField
33806 * @param {Object} config The config object
33809 Roo.bootstrap.NumberField = function(config){
33810 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33813 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33816 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33818 allowDecimals : true,
33820 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33822 decimalSeparator : ".",
33824 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33826 decimalPrecision : 2,
33828 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33830 allowNegative : true,
33833 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33837 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33839 minValue : Number.NEGATIVE_INFINITY,
33841 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33843 maxValue : Number.MAX_VALUE,
33845 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33847 minText : "The minimum value for this field is {0}",
33849 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33851 maxText : "The maximum value for this field is {0}",
33853 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33854 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33856 nanText : "{0} is not a valid number",
33858 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33860 thousandsDelimiter : false,
33862 * @cfg {String} valueAlign alignment of value
33864 valueAlign : "left",
33866 getAutoCreate : function()
33868 var hiddenInput = {
33872 cls: 'hidden-number-input'
33876 hiddenInput.name = this.name;
33881 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33883 this.name = hiddenInput.name;
33885 if(cfg.cn.length > 0) {
33886 cfg.cn.push(hiddenInput);
33893 initEvents : function()
33895 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33897 var allowed = "0123456789";
33899 if(this.allowDecimals){
33900 allowed += this.decimalSeparator;
33903 if(this.allowNegative){
33907 if(this.thousandsDelimiter) {
33911 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33913 var keyPress = function(e){
33915 var k = e.getKey();
33917 var c = e.getCharCode();
33920 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33921 allowed.indexOf(String.fromCharCode(c)) === -1
33927 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33931 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33936 this.el.on("keypress", keyPress, this);
33939 validateValue : function(value)
33942 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33946 var num = this.parseValue(value);
33949 this.markInvalid(String.format(this.nanText, value));
33953 if(num < this.minValue){
33954 this.markInvalid(String.format(this.minText, this.minValue));
33958 if(num > this.maxValue){
33959 this.markInvalid(String.format(this.maxText, this.maxValue));
33966 getValue : function()
33968 var v = this.hiddenEl().getValue();
33970 return this.fixPrecision(this.parseValue(v));
33973 parseValue : function(value)
33975 if(this.thousandsDelimiter) {
33977 r = new RegExp(",", "g");
33978 value = value.replace(r, "");
33981 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33982 return isNaN(value) ? '' : value;
33985 fixPrecision : function(value)
33987 if(this.thousandsDelimiter) {
33989 r = new RegExp(",", "g");
33990 value = value.replace(r, "");
33993 var nan = isNaN(value);
33995 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33996 return nan ? '' : value;
33998 return parseFloat(value).toFixed(this.decimalPrecision);
34001 setValue : function(v)
34003 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
34009 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
34011 this.inputEl().dom.value = (v == '') ? '' :
34012 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
34014 if(!this.allowZero && v === '0') {
34015 this.hiddenEl().dom.value = '';
34016 this.inputEl().dom.value = '';
34023 decimalPrecisionFcn : function(v)
34025 return Math.floor(v);
34028 beforeBlur : function()
34030 var v = this.parseValue(this.getRawValue());
34032 if(v || v === 0 || v === ''){
34037 hiddenEl : function()
34039 return this.el.select('input.hidden-number-input',true).first();
34051 * @class Roo.bootstrap.DocumentSlider
34052 * @extends Roo.bootstrap.Component
34053 * Bootstrap DocumentSlider class
34056 * Create a new DocumentViewer
34057 * @param {Object} config The config object
34060 Roo.bootstrap.DocumentSlider = function(config){
34061 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34068 * Fire after initEvent
34069 * @param {Roo.bootstrap.DocumentSlider} this
34074 * Fire after update
34075 * @param {Roo.bootstrap.DocumentSlider} this
34081 * @param {Roo.bootstrap.DocumentSlider} this
34087 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34093 getAutoCreate : function()
34097 cls : 'roo-document-slider',
34101 cls : 'roo-document-slider-header',
34105 cls : 'roo-document-slider-header-title'
34111 cls : 'roo-document-slider-body',
34115 cls : 'roo-document-slider-prev',
34119 cls : 'fa fa-chevron-left'
34125 cls : 'roo-document-slider-thumb',
34129 cls : 'roo-document-slider-image'
34135 cls : 'roo-document-slider-next',
34139 cls : 'fa fa-chevron-right'
34151 initEvents : function()
34153 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34154 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34156 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34157 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34159 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34160 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34162 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34163 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34165 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34166 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34168 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34169 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34171 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34172 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34174 this.thumbEl.on('click', this.onClick, this);
34176 this.prevIndicator.on('click', this.prev, this);
34178 this.nextIndicator.on('click', this.next, this);
34182 initial : function()
34184 if(this.files.length){
34185 this.indicator = 1;
34189 this.fireEvent('initial', this);
34192 update : function()
34194 this.imageEl.attr('src', this.files[this.indicator - 1]);
34196 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34198 this.prevIndicator.show();
34200 if(this.indicator == 1){
34201 this.prevIndicator.hide();
34204 this.nextIndicator.show();
34206 if(this.indicator == this.files.length){
34207 this.nextIndicator.hide();
34210 this.thumbEl.scrollTo('top');
34212 this.fireEvent('update', this);
34215 onClick : function(e)
34217 e.preventDefault();
34219 this.fireEvent('click', this);
34224 e.preventDefault();
34226 this.indicator = Math.max(1, this.indicator - 1);
34233 e.preventDefault();
34235 this.indicator = Math.min(this.files.length, this.indicator + 1);
34249 * @class Roo.bootstrap.RadioSet
34250 * @extends Roo.bootstrap.Input
34251 * Bootstrap RadioSet class
34252 * @cfg {String} indicatorpos (left|right) default left
34253 * @cfg {Boolean} inline (true|false) inline the element (default true)
34254 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34256 * Create a new RadioSet
34257 * @param {Object} config The config object
34260 Roo.bootstrap.RadioSet = function(config){
34262 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34266 Roo.bootstrap.RadioSet.register(this);
34271 * Fires when the element is checked or unchecked.
34272 * @param {Roo.bootstrap.RadioSet} this This radio
34273 * @param {Roo.bootstrap.Radio} item The checked item
34278 * Fires when the element is click.
34279 * @param {Roo.bootstrap.RadioSet} this This radio set
34280 * @param {Roo.bootstrap.Radio} item The checked item
34281 * @param {Roo.EventObject} e The event object
34288 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34296 indicatorpos : 'left',
34298 getAutoCreate : function()
34302 cls : 'roo-radio-set-label',
34306 html : this.fieldLabel
34310 if (Roo.bootstrap.version == 3) {
34313 if(this.indicatorpos == 'left'){
34316 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34317 tooltip : 'This field is required'
34322 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34323 tooltip : 'This field is required'
34329 cls : 'roo-radio-set-items'
34332 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34334 if (align === 'left' && this.fieldLabel.length) {
34337 cls : "roo-radio-set-right",
34343 if(this.labelWidth > 12){
34344 label.style = "width: " + this.labelWidth + 'px';
34347 if(this.labelWidth < 13 && this.labelmd == 0){
34348 this.labelmd = this.labelWidth;
34351 if(this.labellg > 0){
34352 label.cls += ' col-lg-' + this.labellg;
34353 items.cls += ' col-lg-' + (12 - this.labellg);
34356 if(this.labelmd > 0){
34357 label.cls += ' col-md-' + this.labelmd;
34358 items.cls += ' col-md-' + (12 - this.labelmd);
34361 if(this.labelsm > 0){
34362 label.cls += ' col-sm-' + this.labelsm;
34363 items.cls += ' col-sm-' + (12 - this.labelsm);
34366 if(this.labelxs > 0){
34367 label.cls += ' col-xs-' + this.labelxs;
34368 items.cls += ' col-xs-' + (12 - this.labelxs);
34374 cls : 'roo-radio-set',
34378 cls : 'roo-radio-set-input',
34381 value : this.value ? this.value : ''
34388 if(this.weight.length){
34389 cfg.cls += ' roo-radio-' + this.weight;
34393 cfg.cls += ' roo-radio-set-inline';
34397 ['xs','sm','md','lg'].map(function(size){
34398 if (settings[size]) {
34399 cfg.cls += ' col-' + size + '-' + settings[size];
34407 initEvents : function()
34409 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34410 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34412 if(!this.fieldLabel.length){
34413 this.labelEl.hide();
34416 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34417 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34419 this.indicator = this.indicatorEl();
34421 if(this.indicator){
34422 this.indicator.addClass('invisible');
34425 this.originalValue = this.getValue();
34429 inputEl: function ()
34431 return this.el.select('.roo-radio-set-input', true).first();
34434 getChildContainer : function()
34436 return this.itemsEl;
34439 register : function(item)
34441 this.radioes.push(item);
34445 validate : function()
34447 if(this.getVisibilityEl().hasClass('hidden')){
34453 Roo.each(this.radioes, function(i){
34462 if(this.allowBlank) {
34466 if(this.disabled || valid){
34471 this.markInvalid();
34476 markValid : function()
34478 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34479 this.indicatorEl().removeClass('visible');
34480 this.indicatorEl().addClass('invisible');
34484 if (Roo.bootstrap.version == 3) {
34485 this.el.removeClass([this.invalidClass, this.validClass]);
34486 this.el.addClass(this.validClass);
34488 this.el.removeClass(['is-invalid','is-valid']);
34489 this.el.addClass(['is-valid']);
34491 this.fireEvent('valid', this);
34494 markInvalid : function(msg)
34496 if(this.allowBlank || this.disabled){
34500 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34501 this.indicatorEl().removeClass('invisible');
34502 this.indicatorEl().addClass('visible');
34504 if (Roo.bootstrap.version == 3) {
34505 this.el.removeClass([this.invalidClass, this.validClass]);
34506 this.el.addClass(this.invalidClass);
34508 this.el.removeClass(['is-invalid','is-valid']);
34509 this.el.addClass(['is-invalid']);
34512 this.fireEvent('invalid', this, msg);
34516 setValue : function(v, suppressEvent)
34518 if(this.value === v){
34525 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34528 Roo.each(this.radioes, function(i){
34530 i.el.removeClass('checked');
34533 Roo.each(this.radioes, function(i){
34535 if(i.value === v || i.value.toString() === v.toString()){
34537 i.el.addClass('checked');
34539 if(suppressEvent !== true){
34540 this.fireEvent('check', this, i);
34551 clearInvalid : function(){
34553 if(!this.el || this.preventMark){
34557 this.el.removeClass([this.invalidClass]);
34559 this.fireEvent('valid', this);
34564 Roo.apply(Roo.bootstrap.RadioSet, {
34568 register : function(set)
34570 this.groups[set.name] = set;
34573 get: function(name)
34575 if (typeof(this.groups[name]) == 'undefined') {
34579 return this.groups[name] ;
34585 * Ext JS Library 1.1.1
34586 * Copyright(c) 2006-2007, Ext JS, LLC.
34588 * Originally Released Under LGPL - original licence link has changed is not relivant.
34591 * <script type="text/javascript">
34596 * @class Roo.bootstrap.SplitBar
34597 * @extends Roo.util.Observable
34598 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34602 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34603 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34604 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34605 split.minSize = 100;
34606 split.maxSize = 600;
34607 split.animate = true;
34608 split.on('moved', splitterMoved);
34611 * Create a new SplitBar
34612 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34613 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34614 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34615 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34616 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34617 position of the SplitBar).
34619 Roo.bootstrap.SplitBar = function(cfg){
34624 // dragElement : elm
34625 // resizingElement: el,
34627 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34628 // placement : Roo.bootstrap.SplitBar.LEFT ,
34629 // existingProxy ???
34632 this.el = Roo.get(cfg.dragElement, true);
34633 this.el.dom.unselectable = "on";
34635 this.resizingEl = Roo.get(cfg.resizingElement, true);
34639 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34640 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34643 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34646 * The minimum size of the resizing element. (Defaults to 0)
34652 * The maximum size of the resizing element. (Defaults to 2000)
34655 this.maxSize = 2000;
34658 * Whether to animate the transition to the new size
34661 this.animate = false;
34664 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34667 this.useShim = false;
34672 if(!cfg.existingProxy){
34674 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34676 this.proxy = Roo.get(cfg.existingProxy).dom;
34679 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34682 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34685 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34688 this.dragSpecs = {};
34691 * @private The adapter to use to positon and resize elements
34693 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34694 this.adapter.init(this);
34696 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34698 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34699 this.el.addClass("roo-splitbar-h");
34702 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34703 this.el.addClass("roo-splitbar-v");
34709 * Fires when the splitter is moved (alias for {@link #event-moved})
34710 * @param {Roo.bootstrap.SplitBar} this
34711 * @param {Number} newSize the new width or height
34716 * Fires when the splitter is moved
34717 * @param {Roo.bootstrap.SplitBar} this
34718 * @param {Number} newSize the new width or height
34722 * @event beforeresize
34723 * Fires before the splitter is dragged
34724 * @param {Roo.bootstrap.SplitBar} this
34726 "beforeresize" : true,
34728 "beforeapply" : true
34731 Roo.util.Observable.call(this);
34734 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34735 onStartProxyDrag : function(x, y){
34736 this.fireEvent("beforeresize", this);
34738 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34740 o.enableDisplayMode("block");
34741 // all splitbars share the same overlay
34742 Roo.bootstrap.SplitBar.prototype.overlay = o;
34744 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34745 this.overlay.show();
34746 Roo.get(this.proxy).setDisplayed("block");
34747 var size = this.adapter.getElementSize(this);
34748 this.activeMinSize = this.getMinimumSize();;
34749 this.activeMaxSize = this.getMaximumSize();;
34750 var c1 = size - this.activeMinSize;
34751 var c2 = Math.max(this.activeMaxSize - size, 0);
34752 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34753 this.dd.resetConstraints();
34754 this.dd.setXConstraint(
34755 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34756 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34758 this.dd.setYConstraint(0, 0);
34760 this.dd.resetConstraints();
34761 this.dd.setXConstraint(0, 0);
34762 this.dd.setYConstraint(
34763 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34764 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34767 this.dragSpecs.startSize = size;
34768 this.dragSpecs.startPoint = [x, y];
34769 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34773 * @private Called after the drag operation by the DDProxy
34775 onEndProxyDrag : function(e){
34776 Roo.get(this.proxy).setDisplayed(false);
34777 var endPoint = Roo.lib.Event.getXY(e);
34779 this.overlay.hide();
34782 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34783 newSize = this.dragSpecs.startSize +
34784 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34785 endPoint[0] - this.dragSpecs.startPoint[0] :
34786 this.dragSpecs.startPoint[0] - endPoint[0]
34789 newSize = this.dragSpecs.startSize +
34790 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34791 endPoint[1] - this.dragSpecs.startPoint[1] :
34792 this.dragSpecs.startPoint[1] - endPoint[1]
34795 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34796 if(newSize != this.dragSpecs.startSize){
34797 if(this.fireEvent('beforeapply', this, newSize) !== false){
34798 this.adapter.setElementSize(this, newSize);
34799 this.fireEvent("moved", this, newSize);
34800 this.fireEvent("resize", this, newSize);
34806 * Get the adapter this SplitBar uses
34807 * @return The adapter object
34809 getAdapter : function(){
34810 return this.adapter;
34814 * Set the adapter this SplitBar uses
34815 * @param {Object} adapter A SplitBar adapter object
34817 setAdapter : function(adapter){
34818 this.adapter = adapter;
34819 this.adapter.init(this);
34823 * Gets the minimum size for the resizing element
34824 * @return {Number} The minimum size
34826 getMinimumSize : function(){
34827 return this.minSize;
34831 * Sets the minimum size for the resizing element
34832 * @param {Number} minSize The minimum size
34834 setMinimumSize : function(minSize){
34835 this.minSize = minSize;
34839 * Gets the maximum size for the resizing element
34840 * @return {Number} The maximum size
34842 getMaximumSize : function(){
34843 return this.maxSize;
34847 * Sets the maximum size for the resizing element
34848 * @param {Number} maxSize The maximum size
34850 setMaximumSize : function(maxSize){
34851 this.maxSize = maxSize;
34855 * Sets the initialize size for the resizing element
34856 * @param {Number} size The initial size
34858 setCurrentSize : function(size){
34859 var oldAnimate = this.animate;
34860 this.animate = false;
34861 this.adapter.setElementSize(this, size);
34862 this.animate = oldAnimate;
34866 * Destroy this splitbar.
34867 * @param {Boolean} removeEl True to remove the element
34869 destroy : function(removeEl){
34871 this.shim.remove();
34874 this.proxy.parentNode.removeChild(this.proxy);
34882 * @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.
34884 Roo.bootstrap.SplitBar.createProxy = function(dir){
34885 var proxy = new Roo.Element(document.createElement("div"));
34886 proxy.unselectable();
34887 var cls = 'roo-splitbar-proxy';
34888 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34889 document.body.appendChild(proxy.dom);
34894 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34895 * Default Adapter. It assumes the splitter and resizing element are not positioned
34896 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34898 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34901 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34902 // do nothing for now
34903 init : function(s){
34907 * Called before drag operations to get the current size of the resizing element.
34908 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34910 getElementSize : function(s){
34911 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34912 return s.resizingEl.getWidth();
34914 return s.resizingEl.getHeight();
34919 * Called after drag operations to set the size of the resizing element.
34920 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34921 * @param {Number} newSize The new size to set
34922 * @param {Function} onComplete A function to be invoked when resizing is complete
34924 setElementSize : function(s, newSize, onComplete){
34925 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34927 s.resizingEl.setWidth(newSize);
34929 onComplete(s, newSize);
34932 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34937 s.resizingEl.setHeight(newSize);
34939 onComplete(s, newSize);
34942 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34949 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34950 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34951 * Adapter that moves the splitter element to align with the resized sizing element.
34952 * Used with an absolute positioned SplitBar.
34953 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34954 * document.body, make sure you assign an id to the body element.
34956 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34957 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34958 this.container = Roo.get(container);
34961 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34962 init : function(s){
34963 this.basic.init(s);
34966 getElementSize : function(s){
34967 return this.basic.getElementSize(s);
34970 setElementSize : function(s, newSize, onComplete){
34971 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34974 moveSplitter : function(s){
34975 var yes = Roo.bootstrap.SplitBar;
34976 switch(s.placement){
34978 s.el.setX(s.resizingEl.getRight());
34981 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34984 s.el.setY(s.resizingEl.getBottom());
34987 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34994 * Orientation constant - Create a vertical SplitBar
34998 Roo.bootstrap.SplitBar.VERTICAL = 1;
35001 * Orientation constant - Create a horizontal SplitBar
35005 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
35008 * Placement constant - The resizing element is to the left of the splitter element
35012 Roo.bootstrap.SplitBar.LEFT = 1;
35015 * Placement constant - The resizing element is to the right of the splitter element
35019 Roo.bootstrap.SplitBar.RIGHT = 2;
35022 * Placement constant - The resizing element is positioned above the splitter element
35026 Roo.bootstrap.SplitBar.TOP = 3;
35029 * Placement constant - The resizing element is positioned under splitter element
35033 Roo.bootstrap.SplitBar.BOTTOM = 4;
35034 Roo.namespace("Roo.bootstrap.layout");/*
35036 * Ext JS Library 1.1.1
35037 * Copyright(c) 2006-2007, Ext JS, LLC.
35039 * Originally Released Under LGPL - original licence link has changed is not relivant.
35042 * <script type="text/javascript">
35046 * @class Roo.bootstrap.layout.Manager
35047 * @extends Roo.bootstrap.Component
35048 * Base class for layout managers.
35050 Roo.bootstrap.layout.Manager = function(config)
35052 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
35058 /** false to disable window resize monitoring @type Boolean */
35059 this.monitorWindowResize = true;
35064 * Fires when a layout is performed.
35065 * @param {Roo.LayoutManager} this
35069 * @event regionresized
35070 * Fires when the user resizes a region.
35071 * @param {Roo.LayoutRegion} region The resized region
35072 * @param {Number} newSize The new size (width for east/west, height for north/south)
35074 "regionresized" : true,
35076 * @event regioncollapsed
35077 * Fires when a region is collapsed.
35078 * @param {Roo.LayoutRegion} region The collapsed region
35080 "regioncollapsed" : true,
35082 * @event regionexpanded
35083 * Fires when a region is expanded.
35084 * @param {Roo.LayoutRegion} region The expanded region
35086 "regionexpanded" : true
35088 this.updating = false;
35091 this.el = Roo.get(config.el);
35097 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35102 monitorWindowResize : true,
35108 onRender : function(ct, position)
35111 this.el = Roo.get(ct);
35114 //this.fireEvent('render',this);
35118 initEvents: function()
35122 // ie scrollbar fix
35123 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35124 document.body.scroll = "no";
35125 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35126 this.el.position('relative');
35128 this.id = this.el.id;
35129 this.el.addClass("roo-layout-container");
35130 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35131 if(this.el.dom != document.body ) {
35132 this.el.on('resize', this.layout,this);
35133 this.el.on('show', this.layout,this);
35139 * Returns true if this layout is currently being updated
35140 * @return {Boolean}
35142 isUpdating : function(){
35143 return this.updating;
35147 * Suspend the LayoutManager from doing auto-layouts while
35148 * making multiple add or remove calls
35150 beginUpdate : function(){
35151 this.updating = true;
35155 * Restore auto-layouts and optionally disable the manager from performing a layout
35156 * @param {Boolean} noLayout true to disable a layout update
35158 endUpdate : function(noLayout){
35159 this.updating = false;
35165 layout: function(){
35169 onRegionResized : function(region, newSize){
35170 this.fireEvent("regionresized", region, newSize);
35174 onRegionCollapsed : function(region){
35175 this.fireEvent("regioncollapsed", region);
35178 onRegionExpanded : function(region){
35179 this.fireEvent("regionexpanded", region);
35183 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35184 * performs box-model adjustments.
35185 * @return {Object} The size as an object {width: (the width), height: (the height)}
35187 getViewSize : function()
35190 if(this.el.dom != document.body){
35191 size = this.el.getSize();
35193 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35195 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35196 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35201 * Returns the Element this layout is bound to.
35202 * @return {Roo.Element}
35204 getEl : function(){
35209 * Returns the specified region.
35210 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35211 * @return {Roo.LayoutRegion}
35213 getRegion : function(target){
35214 return this.regions[target.toLowerCase()];
35217 onWindowResize : function(){
35218 if(this.monitorWindowResize){
35225 * Ext JS Library 1.1.1
35226 * Copyright(c) 2006-2007, Ext JS, LLC.
35228 * Originally Released Under LGPL - original licence link has changed is not relivant.
35231 * <script type="text/javascript">
35234 * @class Roo.bootstrap.layout.Border
35235 * @extends Roo.bootstrap.layout.Manager
35236 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35237 * please see: examples/bootstrap/nested.html<br><br>
35239 <b>The container the layout is rendered into can be either the body element or any other element.
35240 If it is not the body element, the container needs to either be an absolute positioned element,
35241 or you will need to add "position:relative" to the css of the container. You will also need to specify
35242 the container size if it is not the body element.</b>
35245 * Create a new Border
35246 * @param {Object} config Configuration options
35248 Roo.bootstrap.layout.Border = function(config){
35249 config = config || {};
35250 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35254 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35255 if(config[region]){
35256 config[region].region = region;
35257 this.addRegion(config[region]);
35263 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35265 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35267 parent : false, // this might point to a 'nest' or a ???
35270 * Creates and adds a new region if it doesn't already exist.
35271 * @param {String} target The target region key (north, south, east, west or center).
35272 * @param {Object} config The regions config object
35273 * @return {BorderLayoutRegion} The new region
35275 addRegion : function(config)
35277 if(!this.regions[config.region]){
35278 var r = this.factory(config);
35279 this.bindRegion(r);
35281 return this.regions[config.region];
35285 bindRegion : function(r){
35286 this.regions[r.config.region] = r;
35288 r.on("visibilitychange", this.layout, this);
35289 r.on("paneladded", this.layout, this);
35290 r.on("panelremoved", this.layout, this);
35291 r.on("invalidated", this.layout, this);
35292 r.on("resized", this.onRegionResized, this);
35293 r.on("collapsed", this.onRegionCollapsed, this);
35294 r.on("expanded", this.onRegionExpanded, this);
35298 * Performs a layout update.
35300 layout : function()
35302 if(this.updating) {
35306 // render all the rebions if they have not been done alreayd?
35307 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35308 if(this.regions[region] && !this.regions[region].bodyEl){
35309 this.regions[region].onRender(this.el)
35313 var size = this.getViewSize();
35314 var w = size.width;
35315 var h = size.height;
35320 //var x = 0, y = 0;
35322 var rs = this.regions;
35323 var north = rs["north"];
35324 var south = rs["south"];
35325 var west = rs["west"];
35326 var east = rs["east"];
35327 var center = rs["center"];
35328 //if(this.hideOnLayout){ // not supported anymore
35329 //c.el.setStyle("display", "none");
35331 if(north && north.isVisible()){
35332 var b = north.getBox();
35333 var m = north.getMargins();
35334 b.width = w - (m.left+m.right);
35337 centerY = b.height + b.y + m.bottom;
35338 centerH -= centerY;
35339 north.updateBox(this.safeBox(b));
35341 if(south && south.isVisible()){
35342 var b = south.getBox();
35343 var m = south.getMargins();
35344 b.width = w - (m.left+m.right);
35346 var totalHeight = (b.height + m.top + m.bottom);
35347 b.y = h - totalHeight + m.top;
35348 centerH -= totalHeight;
35349 south.updateBox(this.safeBox(b));
35351 if(west && west.isVisible()){
35352 var b = west.getBox();
35353 var m = west.getMargins();
35354 b.height = centerH - (m.top+m.bottom);
35356 b.y = centerY + m.top;
35357 var totalWidth = (b.width + m.left + m.right);
35358 centerX += totalWidth;
35359 centerW -= totalWidth;
35360 west.updateBox(this.safeBox(b));
35362 if(east && east.isVisible()){
35363 var b = east.getBox();
35364 var m = east.getMargins();
35365 b.height = centerH - (m.top+m.bottom);
35366 var totalWidth = (b.width + m.left + m.right);
35367 b.x = w - totalWidth + m.left;
35368 b.y = centerY + m.top;
35369 centerW -= totalWidth;
35370 east.updateBox(this.safeBox(b));
35373 var m = center.getMargins();
35375 x: centerX + m.left,
35376 y: centerY + m.top,
35377 width: centerW - (m.left+m.right),
35378 height: centerH - (m.top+m.bottom)
35380 //if(this.hideOnLayout){
35381 //center.el.setStyle("display", "block");
35383 center.updateBox(this.safeBox(centerBox));
35386 this.fireEvent("layout", this);
35390 safeBox : function(box){
35391 box.width = Math.max(0, box.width);
35392 box.height = Math.max(0, box.height);
35397 * Adds a ContentPanel (or subclass) to this layout.
35398 * @param {String} target The target region key (north, south, east, west or center).
35399 * @param {Roo.ContentPanel} panel The panel to add
35400 * @return {Roo.ContentPanel} The added panel
35402 add : function(target, panel){
35404 target = target.toLowerCase();
35405 return this.regions[target].add(panel);
35409 * Remove a ContentPanel (or subclass) to this layout.
35410 * @param {String} target The target region key (north, south, east, west or center).
35411 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35412 * @return {Roo.ContentPanel} The removed panel
35414 remove : function(target, panel){
35415 target = target.toLowerCase();
35416 return this.regions[target].remove(panel);
35420 * Searches all regions for a panel with the specified id
35421 * @param {String} panelId
35422 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35424 findPanel : function(panelId){
35425 var rs = this.regions;
35426 for(var target in rs){
35427 if(typeof rs[target] != "function"){
35428 var p = rs[target].getPanel(panelId);
35438 * Searches all regions for a panel with the specified id and activates (shows) it.
35439 * @param {String/ContentPanel} panelId The panels id or the panel itself
35440 * @return {Roo.ContentPanel} The shown panel or null
35442 showPanel : function(panelId) {
35443 var rs = this.regions;
35444 for(var target in rs){
35445 var r = rs[target];
35446 if(typeof r != "function"){
35447 if(r.hasPanel(panelId)){
35448 return r.showPanel(panelId);
35456 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35457 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35460 restoreState : function(provider){
35462 provider = Roo.state.Manager;
35464 var sm = new Roo.LayoutStateManager();
35465 sm.init(this, provider);
35471 * Adds a xtype elements to the layout.
35475 xtype : 'ContentPanel',
35482 xtype : 'NestedLayoutPanel',
35488 items : [ ... list of content panels or nested layout panels.. ]
35492 * @param {Object} cfg Xtype definition of item to add.
35494 addxtype : function(cfg)
35496 // basically accepts a pannel...
35497 // can accept a layout region..!?!?
35498 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35501 // theory? children can only be panels??
35503 //if (!cfg.xtype.match(/Panel$/)) {
35508 if (typeof(cfg.region) == 'undefined') {
35509 Roo.log("Failed to add Panel, region was not set");
35513 var region = cfg.region;
35519 xitems = cfg.items;
35524 if ( region == 'center') {
35525 Roo.log("Center: " + cfg.title);
35531 case 'Content': // ContentPanel (el, cfg)
35532 case 'Scroll': // ContentPanel (el, cfg)
35534 cfg.autoCreate = cfg.autoCreate || true;
35535 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35537 // var el = this.el.createChild();
35538 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35541 this.add(region, ret);
35545 case 'TreePanel': // our new panel!
35546 cfg.el = this.el.createChild();
35547 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35548 this.add(region, ret);
35553 // create a new Layout (which is a Border Layout...
35555 var clayout = cfg.layout;
35556 clayout.el = this.el.createChild();
35557 clayout.items = clayout.items || [];
35561 // replace this exitems with the clayout ones..
35562 xitems = clayout.items;
35564 // force background off if it's in center...
35565 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35566 cfg.background = false;
35568 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35571 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35572 //console.log('adding nested layout panel ' + cfg.toSource());
35573 this.add(region, ret);
35574 nb = {}; /// find first...
35579 // needs grid and region
35581 //var el = this.getRegion(region).el.createChild();
35583 *var el = this.el.createChild();
35584 // create the grid first...
35585 cfg.grid.container = el;
35586 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35589 if (region == 'center' && this.active ) {
35590 cfg.background = false;
35593 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35595 this.add(region, ret);
35597 if (cfg.background) {
35598 // render grid on panel activation (if panel background)
35599 ret.on('activate', function(gp) {
35600 if (!gp.grid.rendered) {
35601 // gp.grid.render(el);
35605 // cfg.grid.render(el);
35611 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35612 // it was the old xcomponent building that caused this before.
35613 // espeically if border is the top element in the tree.
35623 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35625 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35626 this.add(region, ret);
35630 throw "Can not add '" + cfg.xtype + "' to Border";
35636 this.beginUpdate();
35640 Roo.each(xitems, function(i) {
35641 region = nb && i.region ? i.region : false;
35643 var add = ret.addxtype(i);
35646 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35647 if (!i.background) {
35648 abn[region] = nb[region] ;
35655 // make the last non-background panel active..
35656 //if (nb) { Roo.log(abn); }
35659 for(var r in abn) {
35660 region = this.getRegion(r);
35662 // tried using nb[r], but it does not work..
35664 region.showPanel(abn[r]);
35675 factory : function(cfg)
35678 var validRegions = Roo.bootstrap.layout.Border.regions;
35680 var target = cfg.region;
35683 var r = Roo.bootstrap.layout;
35687 return new r.North(cfg);
35689 return new r.South(cfg);
35691 return new r.East(cfg);
35693 return new r.West(cfg);
35695 return new r.Center(cfg);
35697 throw 'Layout region "'+target+'" not supported.';
35704 * Ext JS Library 1.1.1
35705 * Copyright(c) 2006-2007, Ext JS, LLC.
35707 * Originally Released Under LGPL - original licence link has changed is not relivant.
35710 * <script type="text/javascript">
35714 * @class Roo.bootstrap.layout.Basic
35715 * @extends Roo.util.Observable
35716 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35717 * and does not have a titlebar, tabs or any other features. All it does is size and position
35718 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35719 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35720 * @cfg {string} region the region that it inhabits..
35721 * @cfg {bool} skipConfig skip config?
35725 Roo.bootstrap.layout.Basic = function(config){
35727 this.mgr = config.mgr;
35729 this.position = config.region;
35731 var skipConfig = config.skipConfig;
35735 * @scope Roo.BasicLayoutRegion
35739 * @event beforeremove
35740 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35741 * @param {Roo.LayoutRegion} this
35742 * @param {Roo.ContentPanel} panel The panel
35743 * @param {Object} e The cancel event object
35745 "beforeremove" : true,
35747 * @event invalidated
35748 * Fires when the layout for this region is changed.
35749 * @param {Roo.LayoutRegion} this
35751 "invalidated" : true,
35753 * @event visibilitychange
35754 * Fires when this region is shown or hidden
35755 * @param {Roo.LayoutRegion} this
35756 * @param {Boolean} visibility true or false
35758 "visibilitychange" : true,
35760 * @event paneladded
35761 * Fires when a panel is added.
35762 * @param {Roo.LayoutRegion} this
35763 * @param {Roo.ContentPanel} panel The panel
35765 "paneladded" : true,
35767 * @event panelremoved
35768 * Fires when a panel is removed.
35769 * @param {Roo.LayoutRegion} this
35770 * @param {Roo.ContentPanel} panel The panel
35772 "panelremoved" : true,
35774 * @event beforecollapse
35775 * Fires when this region before collapse.
35776 * @param {Roo.LayoutRegion} this
35778 "beforecollapse" : true,
35781 * Fires when this region is collapsed.
35782 * @param {Roo.LayoutRegion} this
35784 "collapsed" : true,
35787 * Fires when this region is expanded.
35788 * @param {Roo.LayoutRegion} this
35793 * Fires when this region is slid into view.
35794 * @param {Roo.LayoutRegion} this
35796 "slideshow" : true,
35799 * Fires when this region slides out of view.
35800 * @param {Roo.LayoutRegion} this
35802 "slidehide" : true,
35804 * @event panelactivated
35805 * Fires when a panel is activated.
35806 * @param {Roo.LayoutRegion} this
35807 * @param {Roo.ContentPanel} panel The activated panel
35809 "panelactivated" : true,
35812 * Fires when the user resizes this region.
35813 * @param {Roo.LayoutRegion} this
35814 * @param {Number} newSize The new size (width for east/west, height for north/south)
35818 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35819 this.panels = new Roo.util.MixedCollection();
35820 this.panels.getKey = this.getPanelId.createDelegate(this);
35822 this.activePanel = null;
35823 // ensure listeners are added...
35825 if (config.listeners || config.events) {
35826 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35827 listeners : config.listeners || {},
35828 events : config.events || {}
35832 if(skipConfig !== true){
35833 this.applyConfig(config);
35837 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35839 getPanelId : function(p){
35843 applyConfig : function(config){
35844 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35845 this.config = config;
35850 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35851 * the width, for horizontal (north, south) the height.
35852 * @param {Number} newSize The new width or height
35854 resizeTo : function(newSize){
35855 var el = this.el ? this.el :
35856 (this.activePanel ? this.activePanel.getEl() : null);
35858 switch(this.position){
35861 el.setWidth(newSize);
35862 this.fireEvent("resized", this, newSize);
35866 el.setHeight(newSize);
35867 this.fireEvent("resized", this, newSize);
35873 getBox : function(){
35874 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35877 getMargins : function(){
35878 return this.margins;
35881 updateBox : function(box){
35883 var el = this.activePanel.getEl();
35884 el.dom.style.left = box.x + "px";
35885 el.dom.style.top = box.y + "px";
35886 this.activePanel.setSize(box.width, box.height);
35890 * Returns the container element for this region.
35891 * @return {Roo.Element}
35893 getEl : function(){
35894 return this.activePanel;
35898 * Returns true if this region is currently visible.
35899 * @return {Boolean}
35901 isVisible : function(){
35902 return this.activePanel ? true : false;
35905 setActivePanel : function(panel){
35906 panel = this.getPanel(panel);
35907 if(this.activePanel && this.activePanel != panel){
35908 this.activePanel.setActiveState(false);
35909 this.activePanel.getEl().setLeftTop(-10000,-10000);
35911 this.activePanel = panel;
35912 panel.setActiveState(true);
35914 panel.setSize(this.box.width, this.box.height);
35916 this.fireEvent("panelactivated", this, panel);
35917 this.fireEvent("invalidated");
35921 * Show the specified panel.
35922 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35923 * @return {Roo.ContentPanel} The shown panel or null
35925 showPanel : function(panel){
35926 panel = this.getPanel(panel);
35928 this.setActivePanel(panel);
35934 * Get the active panel for this region.
35935 * @return {Roo.ContentPanel} The active panel or null
35937 getActivePanel : function(){
35938 return this.activePanel;
35942 * Add the passed ContentPanel(s)
35943 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35944 * @return {Roo.ContentPanel} The panel added (if only one was added)
35946 add : function(panel){
35947 if(arguments.length > 1){
35948 for(var i = 0, len = arguments.length; i < len; i++) {
35949 this.add(arguments[i]);
35953 if(this.hasPanel(panel)){
35954 this.showPanel(panel);
35957 var el = panel.getEl();
35958 if(el.dom.parentNode != this.mgr.el.dom){
35959 this.mgr.el.dom.appendChild(el.dom);
35961 if(panel.setRegion){
35962 panel.setRegion(this);
35964 this.panels.add(panel);
35965 el.setStyle("position", "absolute");
35966 if(!panel.background){
35967 this.setActivePanel(panel);
35968 if(this.config.initialSize && this.panels.getCount()==1){
35969 this.resizeTo(this.config.initialSize);
35972 this.fireEvent("paneladded", this, panel);
35977 * Returns true if the panel is in this region.
35978 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35979 * @return {Boolean}
35981 hasPanel : function(panel){
35982 if(typeof panel == "object"){ // must be panel obj
35983 panel = panel.getId();
35985 return this.getPanel(panel) ? true : false;
35989 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35990 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35991 * @param {Boolean} preservePanel Overrides the config preservePanel option
35992 * @return {Roo.ContentPanel} The panel that was removed
35994 remove : function(panel, preservePanel){
35995 panel = this.getPanel(panel);
36000 this.fireEvent("beforeremove", this, panel, e);
36001 if(e.cancel === true){
36004 var panelId = panel.getId();
36005 this.panels.removeKey(panelId);
36010 * Returns the panel specified or null if it's not in this region.
36011 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36012 * @return {Roo.ContentPanel}
36014 getPanel : function(id){
36015 if(typeof id == "object"){ // must be panel obj
36018 return this.panels.get(id);
36022 * Returns this regions position (north/south/east/west/center).
36025 getPosition: function(){
36026 return this.position;
36030 * Ext JS Library 1.1.1
36031 * Copyright(c) 2006-2007, Ext JS, LLC.
36033 * Originally Released Under LGPL - original licence link has changed is not relivant.
36036 * <script type="text/javascript">
36040 * @class Roo.bootstrap.layout.Region
36041 * @extends Roo.bootstrap.layout.Basic
36042 * This class represents a region in a layout manager.
36044 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
36045 * @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})
36046 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
36047 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
36048 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
36049 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
36050 * @cfg {String} title The title for the region (overrides panel titles)
36051 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
36052 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
36053 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
36054 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
36055 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
36056 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
36057 * the space available, similar to FireFox 1.5 tabs (defaults to false)
36058 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
36059 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
36060 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
36062 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
36063 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36064 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36065 * @cfg {Number} width For East/West panels
36066 * @cfg {Number} height For North/South panels
36067 * @cfg {Boolean} split To show the splitter
36068 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36070 * @cfg {string} cls Extra CSS classes to add to region
36072 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36073 * @cfg {string} region the region that it inhabits..
36076 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36077 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36079 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36080 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36081 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36083 Roo.bootstrap.layout.Region = function(config)
36085 this.applyConfig(config);
36087 var mgr = config.mgr;
36088 var pos = config.region;
36089 config.skipConfig = true;
36090 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36093 this.onRender(mgr.el);
36096 this.visible = true;
36097 this.collapsed = false;
36098 this.unrendered_panels = [];
36101 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36103 position: '', // set by wrapper (eg. north/south etc..)
36104 unrendered_panels : null, // unrendered panels.
36106 tabPosition : false,
36108 mgr: false, // points to 'Border'
36111 createBody : function(){
36112 /** This region's body element
36113 * @type Roo.Element */
36114 this.bodyEl = this.el.createChild({
36116 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36120 onRender: function(ctr, pos)
36122 var dh = Roo.DomHelper;
36123 /** This region's container element
36124 * @type Roo.Element */
36125 this.el = dh.append(ctr.dom, {
36127 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36129 /** This region's title element
36130 * @type Roo.Element */
36132 this.titleEl = dh.append(this.el.dom, {
36134 unselectable: "on",
36135 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36137 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36138 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36142 this.titleEl.enableDisplayMode();
36143 /** This region's title text element
36144 * @type HTMLElement */
36145 this.titleTextEl = this.titleEl.dom.firstChild;
36146 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36148 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36149 this.closeBtn.enableDisplayMode();
36150 this.closeBtn.on("click", this.closeClicked, this);
36151 this.closeBtn.hide();
36153 this.createBody(this.config);
36154 if(this.config.hideWhenEmpty){
36156 this.on("paneladded", this.validateVisibility, this);
36157 this.on("panelremoved", this.validateVisibility, this);
36159 if(this.autoScroll){
36160 this.bodyEl.setStyle("overflow", "auto");
36162 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36164 //if(c.titlebar !== false){
36165 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36166 this.titleEl.hide();
36168 this.titleEl.show();
36169 if(this.config.title){
36170 this.titleTextEl.innerHTML = this.config.title;
36174 if(this.config.collapsed){
36175 this.collapse(true);
36177 if(this.config.hidden){
36181 if (this.unrendered_panels && this.unrendered_panels.length) {
36182 for (var i =0;i< this.unrendered_panels.length; i++) {
36183 this.add(this.unrendered_panels[i]);
36185 this.unrendered_panels = null;
36191 applyConfig : function(c)
36194 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36195 var dh = Roo.DomHelper;
36196 if(c.titlebar !== false){
36197 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36198 this.collapseBtn.on("click", this.collapse, this);
36199 this.collapseBtn.enableDisplayMode();
36201 if(c.showPin === true || this.showPin){
36202 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36203 this.stickBtn.enableDisplayMode();
36204 this.stickBtn.on("click", this.expand, this);
36205 this.stickBtn.hide();
36210 /** This region's collapsed element
36211 * @type Roo.Element */
36214 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36215 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36218 if(c.floatable !== false){
36219 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36220 this.collapsedEl.on("click", this.collapseClick, this);
36223 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36224 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36225 id: "message", unselectable: "on", style:{"float":"left"}});
36226 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36228 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36229 this.expandBtn.on("click", this.expand, this);
36233 if(this.collapseBtn){
36234 this.collapseBtn.setVisible(c.collapsible == true);
36237 this.cmargins = c.cmargins || this.cmargins ||
36238 (this.position == "west" || this.position == "east" ?
36239 {top: 0, left: 2, right:2, bottom: 0} :
36240 {top: 2, left: 0, right:0, bottom: 2});
36242 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36245 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36247 this.autoScroll = c.autoScroll || false;
36252 this.duration = c.duration || .30;
36253 this.slideDuration = c.slideDuration || .45;
36258 * Returns true if this region is currently visible.
36259 * @return {Boolean}
36261 isVisible : function(){
36262 return this.visible;
36266 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36267 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36269 //setCollapsedTitle : function(title){
36270 // title = title || " ";
36271 // if(this.collapsedTitleTextEl){
36272 // this.collapsedTitleTextEl.innerHTML = title;
36276 getBox : function(){
36278 // if(!this.collapsed){
36279 b = this.el.getBox(false, true);
36281 // b = this.collapsedEl.getBox(false, true);
36286 getMargins : function(){
36287 return this.margins;
36288 //return this.collapsed ? this.cmargins : this.margins;
36291 highlight : function(){
36292 this.el.addClass("x-layout-panel-dragover");
36295 unhighlight : function(){
36296 this.el.removeClass("x-layout-panel-dragover");
36299 updateBox : function(box)
36301 if (!this.bodyEl) {
36302 return; // not rendered yet..
36306 if(!this.collapsed){
36307 this.el.dom.style.left = box.x + "px";
36308 this.el.dom.style.top = box.y + "px";
36309 this.updateBody(box.width, box.height);
36311 this.collapsedEl.dom.style.left = box.x + "px";
36312 this.collapsedEl.dom.style.top = box.y + "px";
36313 this.collapsedEl.setSize(box.width, box.height);
36316 this.tabs.autoSizeTabs();
36320 updateBody : function(w, h)
36323 this.el.setWidth(w);
36324 w -= this.el.getBorderWidth("rl");
36325 if(this.config.adjustments){
36326 w += this.config.adjustments[0];
36329 if(h !== null && h > 0){
36330 this.el.setHeight(h);
36331 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36332 h -= this.el.getBorderWidth("tb");
36333 if(this.config.adjustments){
36334 h += this.config.adjustments[1];
36336 this.bodyEl.setHeight(h);
36338 h = this.tabs.syncHeight(h);
36341 if(this.panelSize){
36342 w = w !== null ? w : this.panelSize.width;
36343 h = h !== null ? h : this.panelSize.height;
36345 if(this.activePanel){
36346 var el = this.activePanel.getEl();
36347 w = w !== null ? w : el.getWidth();
36348 h = h !== null ? h : el.getHeight();
36349 this.panelSize = {width: w, height: h};
36350 this.activePanel.setSize(w, h);
36352 if(Roo.isIE && this.tabs){
36353 this.tabs.el.repaint();
36358 * Returns the container element for this region.
36359 * @return {Roo.Element}
36361 getEl : function(){
36366 * Hides this region.
36369 //if(!this.collapsed){
36370 this.el.dom.style.left = "-2000px";
36373 // this.collapsedEl.dom.style.left = "-2000px";
36374 // this.collapsedEl.hide();
36376 this.visible = false;
36377 this.fireEvent("visibilitychange", this, false);
36381 * Shows this region if it was previously hidden.
36384 //if(!this.collapsed){
36387 // this.collapsedEl.show();
36389 this.visible = true;
36390 this.fireEvent("visibilitychange", this, true);
36393 closeClicked : function(){
36394 if(this.activePanel){
36395 this.remove(this.activePanel);
36399 collapseClick : function(e){
36401 e.stopPropagation();
36404 e.stopPropagation();
36410 * Collapses this region.
36411 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36414 collapse : function(skipAnim, skipCheck = false){
36415 if(this.collapsed) {
36419 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36421 this.collapsed = true;
36423 this.split.el.hide();
36425 if(this.config.animate && skipAnim !== true){
36426 this.fireEvent("invalidated", this);
36427 this.animateCollapse();
36429 this.el.setLocation(-20000,-20000);
36431 this.collapsedEl.show();
36432 this.fireEvent("collapsed", this);
36433 this.fireEvent("invalidated", this);
36439 animateCollapse : function(){
36444 * Expands this region if it was previously collapsed.
36445 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36446 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36449 expand : function(e, skipAnim){
36451 e.stopPropagation();
36453 if(!this.collapsed || this.el.hasActiveFx()) {
36457 this.afterSlideIn();
36460 this.collapsed = false;
36461 if(this.config.animate && skipAnim !== true){
36462 this.animateExpand();
36466 this.split.el.show();
36468 this.collapsedEl.setLocation(-2000,-2000);
36469 this.collapsedEl.hide();
36470 this.fireEvent("invalidated", this);
36471 this.fireEvent("expanded", this);
36475 animateExpand : function(){
36479 initTabs : function()
36481 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36483 var ts = new Roo.bootstrap.panel.Tabs({
36484 el: this.bodyEl.dom,
36486 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36487 disableTooltips: this.config.disableTabTips,
36488 toolbar : this.config.toolbar
36491 if(this.config.hideTabs){
36492 ts.stripWrap.setDisplayed(false);
36495 ts.resizeTabs = this.config.resizeTabs === true;
36496 ts.minTabWidth = this.config.minTabWidth || 40;
36497 ts.maxTabWidth = this.config.maxTabWidth || 250;
36498 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36499 ts.monitorResize = false;
36500 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36501 ts.bodyEl.addClass('roo-layout-tabs-body');
36502 this.panels.each(this.initPanelAsTab, this);
36505 initPanelAsTab : function(panel){
36506 var ti = this.tabs.addTab(
36510 this.config.closeOnTab && panel.isClosable(),
36513 if(panel.tabTip !== undefined){
36514 ti.setTooltip(panel.tabTip);
36516 ti.on("activate", function(){
36517 this.setActivePanel(panel);
36520 if(this.config.closeOnTab){
36521 ti.on("beforeclose", function(t, e){
36523 this.remove(panel);
36527 panel.tabItem = ti;
36532 updatePanelTitle : function(panel, title)
36534 if(this.activePanel == panel){
36535 this.updateTitle(title);
36538 var ti = this.tabs.getTab(panel.getEl().id);
36540 if(panel.tabTip !== undefined){
36541 ti.setTooltip(panel.tabTip);
36546 updateTitle : function(title){
36547 if(this.titleTextEl && !this.config.title){
36548 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36552 setActivePanel : function(panel)
36554 panel = this.getPanel(panel);
36555 if(this.activePanel && this.activePanel != panel){
36556 if(this.activePanel.setActiveState(false) === false){
36560 this.activePanel = panel;
36561 panel.setActiveState(true);
36562 if(this.panelSize){
36563 panel.setSize(this.panelSize.width, this.panelSize.height);
36566 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36568 this.updateTitle(panel.getTitle());
36570 this.fireEvent("invalidated", this);
36572 this.fireEvent("panelactivated", this, panel);
36576 * Shows the specified panel.
36577 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36578 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36580 showPanel : function(panel)
36582 panel = this.getPanel(panel);
36585 var tab = this.tabs.getTab(panel.getEl().id);
36586 if(tab.isHidden()){
36587 this.tabs.unhideTab(tab.id);
36591 this.setActivePanel(panel);
36598 * Get the active panel for this region.
36599 * @return {Roo.ContentPanel} The active panel or null
36601 getActivePanel : function(){
36602 return this.activePanel;
36605 validateVisibility : function(){
36606 if(this.panels.getCount() < 1){
36607 this.updateTitle(" ");
36608 this.closeBtn.hide();
36611 if(!this.isVisible()){
36618 * Adds the passed ContentPanel(s) to this region.
36619 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36620 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36622 add : function(panel)
36624 if(arguments.length > 1){
36625 for(var i = 0, len = arguments.length; i < len; i++) {
36626 this.add(arguments[i]);
36631 // if we have not been rendered yet, then we can not really do much of this..
36632 if (!this.bodyEl) {
36633 this.unrendered_panels.push(panel);
36640 if(this.hasPanel(panel)){
36641 this.showPanel(panel);
36644 panel.setRegion(this);
36645 this.panels.add(panel);
36646 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36647 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36648 // and hide them... ???
36649 this.bodyEl.dom.appendChild(panel.getEl().dom);
36650 if(panel.background !== true){
36651 this.setActivePanel(panel);
36653 this.fireEvent("paneladded", this, panel);
36660 this.initPanelAsTab(panel);
36664 if(panel.background !== true){
36665 this.tabs.activate(panel.getEl().id);
36667 this.fireEvent("paneladded", this, panel);
36672 * Hides the tab for the specified panel.
36673 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36675 hidePanel : function(panel){
36676 if(this.tabs && (panel = this.getPanel(panel))){
36677 this.tabs.hideTab(panel.getEl().id);
36682 * Unhides the tab for a previously hidden panel.
36683 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36685 unhidePanel : function(panel){
36686 if(this.tabs && (panel = this.getPanel(panel))){
36687 this.tabs.unhideTab(panel.getEl().id);
36691 clearPanels : function(){
36692 while(this.panels.getCount() > 0){
36693 this.remove(this.panels.first());
36698 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36699 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36700 * @param {Boolean} preservePanel Overrides the config preservePanel option
36701 * @return {Roo.ContentPanel} The panel that was removed
36703 remove : function(panel, preservePanel)
36705 panel = this.getPanel(panel);
36710 this.fireEvent("beforeremove", this, panel, e);
36711 if(e.cancel === true){
36714 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36715 var panelId = panel.getId();
36716 this.panels.removeKey(panelId);
36718 document.body.appendChild(panel.getEl().dom);
36721 this.tabs.removeTab(panel.getEl().id);
36722 }else if (!preservePanel){
36723 this.bodyEl.dom.removeChild(panel.getEl().dom);
36725 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36726 var p = this.panels.first();
36727 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36728 tempEl.appendChild(p.getEl().dom);
36729 this.bodyEl.update("");
36730 this.bodyEl.dom.appendChild(p.getEl().dom);
36732 this.updateTitle(p.getTitle());
36734 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36735 this.setActivePanel(p);
36737 panel.setRegion(null);
36738 if(this.activePanel == panel){
36739 this.activePanel = null;
36741 if(this.config.autoDestroy !== false && preservePanel !== true){
36742 try{panel.destroy();}catch(e){}
36744 this.fireEvent("panelremoved", this, panel);
36749 * Returns the TabPanel component used by this region
36750 * @return {Roo.TabPanel}
36752 getTabs : function(){
36756 createTool : function(parentEl, className){
36757 var btn = Roo.DomHelper.append(parentEl, {
36759 cls: "x-layout-tools-button",
36762 cls: "roo-layout-tools-button-inner " + className,
36766 btn.addClassOnOver("roo-layout-tools-button-over");
36771 * Ext JS Library 1.1.1
36772 * Copyright(c) 2006-2007, Ext JS, LLC.
36774 * Originally Released Under LGPL - original licence link has changed is not relivant.
36777 * <script type="text/javascript">
36783 * @class Roo.SplitLayoutRegion
36784 * @extends Roo.LayoutRegion
36785 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36787 Roo.bootstrap.layout.Split = function(config){
36788 this.cursor = config.cursor;
36789 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36792 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36794 splitTip : "Drag to resize.",
36795 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36796 useSplitTips : false,
36798 applyConfig : function(config){
36799 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36802 onRender : function(ctr,pos) {
36804 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36805 if(!this.config.split){
36810 var splitEl = Roo.DomHelper.append(ctr.dom, {
36812 id: this.el.id + "-split",
36813 cls: "roo-layout-split roo-layout-split-"+this.position,
36816 /** The SplitBar for this region
36817 * @type Roo.SplitBar */
36818 // does not exist yet...
36819 Roo.log([this.position, this.orientation]);
36821 this.split = new Roo.bootstrap.SplitBar({
36822 dragElement : splitEl,
36823 resizingElement: this.el,
36824 orientation : this.orientation
36827 this.split.on("moved", this.onSplitMove, this);
36828 this.split.useShim = this.config.useShim === true;
36829 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36830 if(this.useSplitTips){
36831 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36833 //if(config.collapsible){
36834 // this.split.el.on("dblclick", this.collapse, this);
36837 if(typeof this.config.minSize != "undefined"){
36838 this.split.minSize = this.config.minSize;
36840 if(typeof this.config.maxSize != "undefined"){
36841 this.split.maxSize = this.config.maxSize;
36843 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36844 this.hideSplitter();
36849 getHMaxSize : function(){
36850 var cmax = this.config.maxSize || 10000;
36851 var center = this.mgr.getRegion("center");
36852 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36855 getVMaxSize : function(){
36856 var cmax = this.config.maxSize || 10000;
36857 var center = this.mgr.getRegion("center");
36858 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36861 onSplitMove : function(split, newSize){
36862 this.fireEvent("resized", this, newSize);
36866 * Returns the {@link Roo.SplitBar} for this region.
36867 * @return {Roo.SplitBar}
36869 getSplitBar : function(){
36874 this.hideSplitter();
36875 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36878 hideSplitter : function(){
36880 this.split.el.setLocation(-2000,-2000);
36881 this.split.el.hide();
36887 this.split.el.show();
36889 Roo.bootstrap.layout.Split.superclass.show.call(this);
36892 beforeSlide: function(){
36893 if(Roo.isGecko){// firefox overflow auto bug workaround
36894 this.bodyEl.clip();
36896 this.tabs.bodyEl.clip();
36898 if(this.activePanel){
36899 this.activePanel.getEl().clip();
36901 if(this.activePanel.beforeSlide){
36902 this.activePanel.beforeSlide();
36908 afterSlide : function(){
36909 if(Roo.isGecko){// firefox overflow auto bug workaround
36910 this.bodyEl.unclip();
36912 this.tabs.bodyEl.unclip();
36914 if(this.activePanel){
36915 this.activePanel.getEl().unclip();
36916 if(this.activePanel.afterSlide){
36917 this.activePanel.afterSlide();
36923 initAutoHide : function(){
36924 if(this.autoHide !== false){
36925 if(!this.autoHideHd){
36926 var st = new Roo.util.DelayedTask(this.slideIn, this);
36927 this.autoHideHd = {
36928 "mouseout": function(e){
36929 if(!e.within(this.el, true)){
36933 "mouseover" : function(e){
36939 this.el.on(this.autoHideHd);
36943 clearAutoHide : function(){
36944 if(this.autoHide !== false){
36945 this.el.un("mouseout", this.autoHideHd.mouseout);
36946 this.el.un("mouseover", this.autoHideHd.mouseover);
36950 clearMonitor : function(){
36951 Roo.get(document).un("click", this.slideInIf, this);
36954 // these names are backwards but not changed for compat
36955 slideOut : function(){
36956 if(this.isSlid || this.el.hasActiveFx()){
36959 this.isSlid = true;
36960 if(this.collapseBtn){
36961 this.collapseBtn.hide();
36963 this.closeBtnState = this.closeBtn.getStyle('display');
36964 this.closeBtn.hide();
36966 this.stickBtn.show();
36969 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36970 this.beforeSlide();
36971 this.el.setStyle("z-index", 10001);
36972 this.el.slideIn(this.getSlideAnchor(), {
36973 callback: function(){
36975 this.initAutoHide();
36976 Roo.get(document).on("click", this.slideInIf, this);
36977 this.fireEvent("slideshow", this);
36984 afterSlideIn : function(){
36985 this.clearAutoHide();
36986 this.isSlid = false;
36987 this.clearMonitor();
36988 this.el.setStyle("z-index", "");
36989 if(this.collapseBtn){
36990 this.collapseBtn.show();
36992 this.closeBtn.setStyle('display', this.closeBtnState);
36994 this.stickBtn.hide();
36996 this.fireEvent("slidehide", this);
36999 slideIn : function(cb){
37000 if(!this.isSlid || this.el.hasActiveFx()){
37004 this.isSlid = false;
37005 this.beforeSlide();
37006 this.el.slideOut(this.getSlideAnchor(), {
37007 callback: function(){
37008 this.el.setLeftTop(-10000, -10000);
37010 this.afterSlideIn();
37018 slideInIf : function(e){
37019 if(!e.within(this.el)){
37024 animateCollapse : function(){
37025 this.beforeSlide();
37026 this.el.setStyle("z-index", 20000);
37027 var anchor = this.getSlideAnchor();
37028 this.el.slideOut(anchor, {
37029 callback : function(){
37030 this.el.setStyle("z-index", "");
37031 this.collapsedEl.slideIn(anchor, {duration:.3});
37033 this.el.setLocation(-10000,-10000);
37035 this.fireEvent("collapsed", this);
37042 animateExpand : function(){
37043 this.beforeSlide();
37044 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
37045 this.el.setStyle("z-index", 20000);
37046 this.collapsedEl.hide({
37049 this.el.slideIn(this.getSlideAnchor(), {
37050 callback : function(){
37051 this.el.setStyle("z-index", "");
37054 this.split.el.show();
37056 this.fireEvent("invalidated", this);
37057 this.fireEvent("expanded", this);
37085 getAnchor : function(){
37086 return this.anchors[this.position];
37089 getCollapseAnchor : function(){
37090 return this.canchors[this.position];
37093 getSlideAnchor : function(){
37094 return this.sanchors[this.position];
37097 getAlignAdj : function(){
37098 var cm = this.cmargins;
37099 switch(this.position){
37115 getExpandAdj : function(){
37116 var c = this.collapsedEl, cm = this.cmargins;
37117 switch(this.position){
37119 return [-(cm.right+c.getWidth()+cm.left), 0];
37122 return [cm.right+c.getWidth()+cm.left, 0];
37125 return [0, -(cm.top+cm.bottom+c.getHeight())];
37128 return [0, cm.top+cm.bottom+c.getHeight()];
37134 * Ext JS Library 1.1.1
37135 * Copyright(c) 2006-2007, Ext JS, LLC.
37137 * Originally Released Under LGPL - original licence link has changed is not relivant.
37140 * <script type="text/javascript">
37143 * These classes are private internal classes
37145 Roo.bootstrap.layout.Center = function(config){
37146 config.region = "center";
37147 Roo.bootstrap.layout.Region.call(this, config);
37148 this.visible = true;
37149 this.minWidth = config.minWidth || 20;
37150 this.minHeight = config.minHeight || 20;
37153 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37155 // center panel can't be hidden
37159 // center panel can't be hidden
37162 getMinWidth: function(){
37163 return this.minWidth;
37166 getMinHeight: function(){
37167 return this.minHeight;
37181 Roo.bootstrap.layout.North = function(config)
37183 config.region = 'north';
37184 config.cursor = 'n-resize';
37186 Roo.bootstrap.layout.Split.call(this, config);
37190 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37191 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37192 this.split.el.addClass("roo-layout-split-v");
37194 var size = config.initialSize || config.height;
37195 if(typeof size != "undefined"){
37196 this.el.setHeight(size);
37199 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37201 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37205 getBox : function(){
37206 if(this.collapsed){
37207 return this.collapsedEl.getBox();
37209 var box = this.el.getBox();
37211 box.height += this.split.el.getHeight();
37216 updateBox : function(box){
37217 if(this.split && !this.collapsed){
37218 box.height -= this.split.el.getHeight();
37219 this.split.el.setLeft(box.x);
37220 this.split.el.setTop(box.y+box.height);
37221 this.split.el.setWidth(box.width);
37223 if(this.collapsed){
37224 this.updateBody(box.width, null);
37226 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37234 Roo.bootstrap.layout.South = function(config){
37235 config.region = 'south';
37236 config.cursor = 's-resize';
37237 Roo.bootstrap.layout.Split.call(this, config);
37239 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37240 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37241 this.split.el.addClass("roo-layout-split-v");
37243 var size = config.initialSize || config.height;
37244 if(typeof size != "undefined"){
37245 this.el.setHeight(size);
37249 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37250 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37251 getBox : function(){
37252 if(this.collapsed){
37253 return this.collapsedEl.getBox();
37255 var box = this.el.getBox();
37257 var sh = this.split.el.getHeight();
37264 updateBox : function(box){
37265 if(this.split && !this.collapsed){
37266 var sh = this.split.el.getHeight();
37269 this.split.el.setLeft(box.x);
37270 this.split.el.setTop(box.y-sh);
37271 this.split.el.setWidth(box.width);
37273 if(this.collapsed){
37274 this.updateBody(box.width, null);
37276 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37280 Roo.bootstrap.layout.East = function(config){
37281 config.region = "east";
37282 config.cursor = "e-resize";
37283 Roo.bootstrap.layout.Split.call(this, config);
37285 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37286 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37287 this.split.el.addClass("roo-layout-split-h");
37289 var size = config.initialSize || config.width;
37290 if(typeof size != "undefined"){
37291 this.el.setWidth(size);
37294 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37295 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37296 getBox : function(){
37297 if(this.collapsed){
37298 return this.collapsedEl.getBox();
37300 var box = this.el.getBox();
37302 var sw = this.split.el.getWidth();
37309 updateBox : function(box){
37310 if(this.split && !this.collapsed){
37311 var sw = this.split.el.getWidth();
37313 this.split.el.setLeft(box.x);
37314 this.split.el.setTop(box.y);
37315 this.split.el.setHeight(box.height);
37318 if(this.collapsed){
37319 this.updateBody(null, box.height);
37321 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37325 Roo.bootstrap.layout.West = function(config){
37326 config.region = "west";
37327 config.cursor = "w-resize";
37329 Roo.bootstrap.layout.Split.call(this, config);
37331 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37332 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37333 this.split.el.addClass("roo-layout-split-h");
37337 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37338 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37340 onRender: function(ctr, pos)
37342 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37343 var size = this.config.initialSize || this.config.width;
37344 if(typeof size != "undefined"){
37345 this.el.setWidth(size);
37349 getBox : function(){
37350 if(this.collapsed){
37351 return this.collapsedEl.getBox();
37353 var box = this.el.getBox();
37355 box.width += this.split.el.getWidth();
37360 updateBox : function(box){
37361 if(this.split && !this.collapsed){
37362 var sw = this.split.el.getWidth();
37364 this.split.el.setLeft(box.x+box.width);
37365 this.split.el.setTop(box.y);
37366 this.split.el.setHeight(box.height);
37368 if(this.collapsed){
37369 this.updateBody(null, box.height);
37371 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37373 });Roo.namespace("Roo.bootstrap.panel");/*
37375 * Ext JS Library 1.1.1
37376 * Copyright(c) 2006-2007, Ext JS, LLC.
37378 * Originally Released Under LGPL - original licence link has changed is not relivant.
37381 * <script type="text/javascript">
37384 * @class Roo.ContentPanel
37385 * @extends Roo.util.Observable
37386 * A basic ContentPanel element.
37387 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37388 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37389 * @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
37390 * @cfg {Boolean} closable True if the panel can be closed/removed
37391 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37392 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37393 * @cfg {Toolbar} toolbar A toolbar for this panel
37394 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37395 * @cfg {String} title The title for this panel
37396 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37397 * @cfg {String} url Calls {@link #setUrl} with this value
37398 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37399 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37400 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37401 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37402 * @cfg {Boolean} badges render the badges
37405 * Create a new ContentPanel.
37406 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37407 * @param {String/Object} config A string to set only the title or a config object
37408 * @param {String} content (optional) Set the HTML content for this panel
37409 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37411 Roo.bootstrap.panel.Content = function( config){
37413 this.tpl = config.tpl || false;
37415 var el = config.el;
37416 var content = config.content;
37418 if(config.autoCreate){ // xtype is available if this is called from factory
37421 this.el = Roo.get(el);
37422 if(!this.el && config && config.autoCreate){
37423 if(typeof config.autoCreate == "object"){
37424 if(!config.autoCreate.id){
37425 config.autoCreate.id = config.id||el;
37427 this.el = Roo.DomHelper.append(document.body,
37428 config.autoCreate, true);
37430 var elcfg = { tag: "div",
37431 cls: "roo-layout-inactive-content",
37435 elcfg.html = config.html;
37439 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37442 this.closable = false;
37443 this.loaded = false;
37444 this.active = false;
37447 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37449 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37451 this.wrapEl = this.el; //this.el.wrap();
37453 if (config.toolbar.items) {
37454 ti = config.toolbar.items ;
37455 delete config.toolbar.items ;
37459 this.toolbar.render(this.wrapEl, 'before');
37460 for(var i =0;i < ti.length;i++) {
37461 // Roo.log(['add child', items[i]]);
37462 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37464 this.toolbar.items = nitems;
37465 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37466 delete config.toolbar;
37470 // xtype created footer. - not sure if will work as we normally have to render first..
37471 if (this.footer && !this.footer.el && this.footer.xtype) {
37472 if (!this.wrapEl) {
37473 this.wrapEl = this.el.wrap();
37476 this.footer.container = this.wrapEl.createChild();
37478 this.footer = Roo.factory(this.footer, Roo);
37483 if(typeof config == "string"){
37484 this.title = config;
37486 Roo.apply(this, config);
37490 this.resizeEl = Roo.get(this.resizeEl, true);
37492 this.resizeEl = this.el;
37494 // handle view.xtype
37502 * Fires when this panel is activated.
37503 * @param {Roo.ContentPanel} this
37507 * @event deactivate
37508 * Fires when this panel is activated.
37509 * @param {Roo.ContentPanel} this
37511 "deactivate" : true,
37515 * Fires when this panel is resized if fitToFrame is true.
37516 * @param {Roo.ContentPanel} this
37517 * @param {Number} width The width after any component adjustments
37518 * @param {Number} height The height after any component adjustments
37524 * Fires when this tab is created
37525 * @param {Roo.ContentPanel} this
37536 if(this.autoScroll){
37537 this.resizeEl.setStyle("overflow", "auto");
37539 // fix randome scrolling
37540 //this.el.on('scroll', function() {
37541 // Roo.log('fix random scolling');
37542 // this.scrollTo('top',0);
37545 content = content || this.content;
37547 this.setContent(content);
37549 if(config && config.url){
37550 this.setUrl(this.url, this.params, this.loadOnce);
37555 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37557 if (this.view && typeof(this.view.xtype) != 'undefined') {
37558 this.view.el = this.el.appendChild(document.createElement("div"));
37559 this.view = Roo.factory(this.view);
37560 this.view.render && this.view.render(false, '');
37564 this.fireEvent('render', this);
37567 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37571 setRegion : function(region){
37572 this.region = region;
37573 this.setActiveClass(region && !this.background);
37577 setActiveClass: function(state)
37580 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37581 this.el.setStyle('position','relative');
37583 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37584 this.el.setStyle('position', 'absolute');
37589 * Returns the toolbar for this Panel if one was configured.
37590 * @return {Roo.Toolbar}
37592 getToolbar : function(){
37593 return this.toolbar;
37596 setActiveState : function(active)
37598 this.active = active;
37599 this.setActiveClass(active);
37601 if(this.fireEvent("deactivate", this) === false){
37606 this.fireEvent("activate", this);
37610 * Updates this panel's element
37611 * @param {String} content The new content
37612 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37614 setContent : function(content, loadScripts){
37615 this.el.update(content, loadScripts);
37618 ignoreResize : function(w, h){
37619 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37622 this.lastSize = {width: w, height: h};
37627 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37628 * @return {Roo.UpdateManager} The UpdateManager
37630 getUpdateManager : function(){
37631 return this.el.getUpdateManager();
37634 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37635 * @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:
37638 url: "your-url.php",
37639 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37640 callback: yourFunction,
37641 scope: yourObject, //(optional scope)
37644 text: "Loading...",
37649 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37650 * 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.
37651 * @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}
37652 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37653 * @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.
37654 * @return {Roo.ContentPanel} this
37657 var um = this.el.getUpdateManager();
37658 um.update.apply(um, arguments);
37664 * 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.
37665 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37666 * @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)
37667 * @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)
37668 * @return {Roo.UpdateManager} The UpdateManager
37670 setUrl : function(url, params, loadOnce){
37671 if(this.refreshDelegate){
37672 this.removeListener("activate", this.refreshDelegate);
37674 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37675 this.on("activate", this.refreshDelegate);
37676 return this.el.getUpdateManager();
37679 _handleRefresh : function(url, params, loadOnce){
37680 if(!loadOnce || !this.loaded){
37681 var updater = this.el.getUpdateManager();
37682 updater.update(url, params, this._setLoaded.createDelegate(this));
37686 _setLoaded : function(){
37687 this.loaded = true;
37691 * Returns this panel's id
37694 getId : function(){
37699 * Returns this panel's element - used by regiosn to add.
37700 * @return {Roo.Element}
37702 getEl : function(){
37703 return this.wrapEl || this.el;
37708 adjustForComponents : function(width, height)
37710 //Roo.log('adjustForComponents ');
37711 if(this.resizeEl != this.el){
37712 width -= this.el.getFrameWidth('lr');
37713 height -= this.el.getFrameWidth('tb');
37716 var te = this.toolbar.getEl();
37717 te.setWidth(width);
37718 height -= te.getHeight();
37721 var te = this.footer.getEl();
37722 te.setWidth(width);
37723 height -= te.getHeight();
37727 if(this.adjustments){
37728 width += this.adjustments[0];
37729 height += this.adjustments[1];
37731 return {"width": width, "height": height};
37734 setSize : function(width, height){
37735 if(this.fitToFrame && !this.ignoreResize(width, height)){
37736 if(this.fitContainer && this.resizeEl != this.el){
37737 this.el.setSize(width, height);
37739 var size = this.adjustForComponents(width, height);
37740 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37741 this.fireEvent('resize', this, size.width, size.height);
37746 * Returns this panel's title
37749 getTitle : function(){
37751 if (typeof(this.title) != 'object') {
37756 for (var k in this.title) {
37757 if (!this.title.hasOwnProperty(k)) {
37761 if (k.indexOf('-') >= 0) {
37762 var s = k.split('-');
37763 for (var i = 0; i<s.length; i++) {
37764 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37767 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37774 * Set this panel's title
37775 * @param {String} title
37777 setTitle : function(title){
37778 this.title = title;
37780 this.region.updatePanelTitle(this, title);
37785 * Returns true is this panel was configured to be closable
37786 * @return {Boolean}
37788 isClosable : function(){
37789 return this.closable;
37792 beforeSlide : function(){
37794 this.resizeEl.clip();
37797 afterSlide : function(){
37799 this.resizeEl.unclip();
37803 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37804 * Will fail silently if the {@link #setUrl} method has not been called.
37805 * This does not activate the panel, just updates its content.
37807 refresh : function(){
37808 if(this.refreshDelegate){
37809 this.loaded = false;
37810 this.refreshDelegate();
37815 * Destroys this panel
37817 destroy : function(){
37818 this.el.removeAllListeners();
37819 var tempEl = document.createElement("span");
37820 tempEl.appendChild(this.el.dom);
37821 tempEl.innerHTML = "";
37827 * form - if the content panel contains a form - this is a reference to it.
37828 * @type {Roo.form.Form}
37832 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37833 * This contains a reference to it.
37839 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37849 * @param {Object} cfg Xtype definition of item to add.
37853 getChildContainer: function () {
37854 return this.getEl();
37859 var ret = new Roo.factory(cfg);
37864 if (cfg.xtype.match(/^Form$/)) {
37867 //if (this.footer) {
37868 // el = this.footer.container.insertSibling(false, 'before');
37870 el = this.el.createChild();
37873 this.form = new Roo.form.Form(cfg);
37876 if ( this.form.allItems.length) {
37877 this.form.render(el.dom);
37881 // should only have one of theses..
37882 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37883 // views.. should not be just added - used named prop 'view''
37885 cfg.el = this.el.appendChild(document.createElement("div"));
37888 var ret = new Roo.factory(cfg);
37890 ret.render && ret.render(false, ''); // render blank..
37900 * @class Roo.bootstrap.panel.Grid
37901 * @extends Roo.bootstrap.panel.Content
37903 * Create a new GridPanel.
37904 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37905 * @param {Object} config A the config object
37911 Roo.bootstrap.panel.Grid = function(config)
37915 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37916 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37918 config.el = this.wrapper;
37919 //this.el = this.wrapper;
37921 if (config.container) {
37922 // ctor'ed from a Border/panel.grid
37925 this.wrapper.setStyle("overflow", "hidden");
37926 this.wrapper.addClass('roo-grid-container');
37931 if(config.toolbar){
37932 var tool_el = this.wrapper.createChild();
37933 this.toolbar = Roo.factory(config.toolbar);
37935 if (config.toolbar.items) {
37936 ti = config.toolbar.items ;
37937 delete config.toolbar.items ;
37941 this.toolbar.render(tool_el);
37942 for(var i =0;i < ti.length;i++) {
37943 // Roo.log(['add child', items[i]]);
37944 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37946 this.toolbar.items = nitems;
37948 delete config.toolbar;
37951 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37952 config.grid.scrollBody = true;;
37953 config.grid.monitorWindowResize = false; // turn off autosizing
37954 config.grid.autoHeight = false;
37955 config.grid.autoWidth = false;
37957 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37959 if (config.background) {
37960 // render grid on panel activation (if panel background)
37961 this.on('activate', function(gp) {
37962 if (!gp.grid.rendered) {
37963 gp.grid.render(this.wrapper);
37964 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37969 this.grid.render(this.wrapper);
37970 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37973 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37974 // ??? needed ??? config.el = this.wrapper;
37979 // xtype created footer. - not sure if will work as we normally have to render first..
37980 if (this.footer && !this.footer.el && this.footer.xtype) {
37982 var ctr = this.grid.getView().getFooterPanel(true);
37983 this.footer.dataSource = this.grid.dataSource;
37984 this.footer = Roo.factory(this.footer, Roo);
37985 this.footer.render(ctr);
37995 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37996 getId : function(){
37997 return this.grid.id;
38001 * Returns the grid for this panel
38002 * @return {Roo.bootstrap.Table}
38004 getGrid : function(){
38008 setSize : function(width, height){
38009 if(!this.ignoreResize(width, height)){
38010 var grid = this.grid;
38011 var size = this.adjustForComponents(width, height);
38012 var gridel = grid.getGridEl();
38013 gridel.setSize(size.width, size.height);
38015 var thd = grid.getGridEl().select('thead',true).first();
38016 var tbd = grid.getGridEl().select('tbody', true).first();
38018 tbd.setSize(width, height - thd.getHeight());
38027 beforeSlide : function(){
38028 this.grid.getView().scroller.clip();
38031 afterSlide : function(){
38032 this.grid.getView().scroller.unclip();
38035 destroy : function(){
38036 this.grid.destroy();
38038 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
38043 * @class Roo.bootstrap.panel.Nest
38044 * @extends Roo.bootstrap.panel.Content
38046 * Create a new Panel, that can contain a layout.Border.
38049 * @param {Roo.BorderLayout} layout The layout for this panel
38050 * @param {String/Object} config A string to set only the title or a config object
38052 Roo.bootstrap.panel.Nest = function(config)
38054 // construct with only one argument..
38055 /* FIXME - implement nicer consturctors
38056 if (layout.layout) {
38058 layout = config.layout;
38059 delete config.layout;
38061 if (layout.xtype && !layout.getEl) {
38062 // then layout needs constructing..
38063 layout = Roo.factory(layout, Roo);
38067 config.el = config.layout.getEl();
38069 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38071 config.layout.monitorWindowResize = false; // turn off autosizing
38072 this.layout = config.layout;
38073 this.layout.getEl().addClass("roo-layout-nested-layout");
38074 this.layout.parent = this;
38081 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38083 setSize : function(width, height){
38084 if(!this.ignoreResize(width, height)){
38085 var size = this.adjustForComponents(width, height);
38086 var el = this.layout.getEl();
38087 if (size.height < 1) {
38088 el.setWidth(size.width);
38090 el.setSize(size.width, size.height);
38092 var touch = el.dom.offsetWidth;
38093 this.layout.layout();
38094 // ie requires a double layout on the first pass
38095 if(Roo.isIE && !this.initialized){
38096 this.initialized = true;
38097 this.layout.layout();
38102 // activate all subpanels if not currently active..
38104 setActiveState : function(active){
38105 this.active = active;
38106 this.setActiveClass(active);
38109 this.fireEvent("deactivate", this);
38113 this.fireEvent("activate", this);
38114 // not sure if this should happen before or after..
38115 if (!this.layout) {
38116 return; // should not happen..
38119 for (var r in this.layout.regions) {
38120 reg = this.layout.getRegion(r);
38121 if (reg.getActivePanel()) {
38122 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38123 reg.setActivePanel(reg.getActivePanel());
38126 if (!reg.panels.length) {
38129 reg.showPanel(reg.getPanel(0));
38138 * Returns the nested BorderLayout for this panel
38139 * @return {Roo.BorderLayout}
38141 getLayout : function(){
38142 return this.layout;
38146 * Adds a xtype elements to the layout of the nested panel
38150 xtype : 'ContentPanel',
38157 xtype : 'NestedLayoutPanel',
38163 items : [ ... list of content panels or nested layout panels.. ]
38167 * @param {Object} cfg Xtype definition of item to add.
38169 addxtype : function(cfg) {
38170 return this.layout.addxtype(cfg);
38175 * Ext JS Library 1.1.1
38176 * Copyright(c) 2006-2007, Ext JS, LLC.
38178 * Originally Released Under LGPL - original licence link has changed is not relivant.
38181 * <script type="text/javascript">
38184 * @class Roo.TabPanel
38185 * @extends Roo.util.Observable
38186 * A lightweight tab container.
38190 // basic tabs 1, built from existing content
38191 var tabs = new Roo.TabPanel("tabs1");
38192 tabs.addTab("script", "View Script");
38193 tabs.addTab("markup", "View Markup");
38194 tabs.activate("script");
38196 // more advanced tabs, built from javascript
38197 var jtabs = new Roo.TabPanel("jtabs");
38198 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38200 // set up the UpdateManager
38201 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38202 var updater = tab2.getUpdateManager();
38203 updater.setDefaultUrl("ajax1.htm");
38204 tab2.on('activate', updater.refresh, updater, true);
38206 // Use setUrl for Ajax loading
38207 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38208 tab3.setUrl("ajax2.htm", null, true);
38211 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38214 jtabs.activate("jtabs-1");
38217 * Create a new TabPanel.
38218 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38219 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38221 Roo.bootstrap.panel.Tabs = function(config){
38223 * The container element for this TabPanel.
38224 * @type Roo.Element
38226 this.el = Roo.get(config.el);
38229 if(typeof config == "boolean"){
38230 this.tabPosition = config ? "bottom" : "top";
38232 Roo.apply(this, config);
38236 if(this.tabPosition == "bottom"){
38237 // if tabs are at the bottom = create the body first.
38238 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38239 this.el.addClass("roo-tabs-bottom");
38241 // next create the tabs holders
38243 if (this.tabPosition == "west"){
38245 var reg = this.region; // fake it..
38247 if (!reg.mgr.parent) {
38250 reg = reg.mgr.parent.region;
38252 Roo.log("got nest?");
38254 if (reg.mgr.getRegion('west')) {
38255 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38256 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38257 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38258 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38259 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38267 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38268 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38269 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38270 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38275 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38278 // finally - if tabs are at the top, then create the body last..
38279 if(this.tabPosition != "bottom"){
38280 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38281 * @type Roo.Element
38283 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38284 this.el.addClass("roo-tabs-top");
38288 this.bodyEl.setStyle("position", "relative");
38290 this.active = null;
38291 this.activateDelegate = this.activate.createDelegate(this);
38296 * Fires when the active tab changes
38297 * @param {Roo.TabPanel} this
38298 * @param {Roo.TabPanelItem} activePanel The new active tab
38302 * @event beforetabchange
38303 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38304 * @param {Roo.TabPanel} this
38305 * @param {Object} e Set cancel to true on this object to cancel the tab change
38306 * @param {Roo.TabPanelItem} tab The tab being changed to
38308 "beforetabchange" : true
38311 Roo.EventManager.onWindowResize(this.onResize, this);
38312 this.cpad = this.el.getPadding("lr");
38313 this.hiddenCount = 0;
38316 // toolbar on the tabbar support...
38317 if (this.toolbar) {
38318 alert("no toolbar support yet");
38319 this.toolbar = false;
38321 var tcfg = this.toolbar;
38322 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38323 this.toolbar = new Roo.Toolbar(tcfg);
38324 if (Roo.isSafari) {
38325 var tbl = tcfg.container.child('table', true);
38326 tbl.setAttribute('width', '100%');
38334 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38337 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38339 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38341 tabPosition : "top",
38343 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38345 currentTabWidth : 0,
38347 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38351 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38355 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38357 preferredTabWidth : 175,
38359 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38361 resizeTabs : false,
38363 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38365 monitorResize : true,
38367 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38369 toolbar : false, // set by caller..
38371 region : false, /// set by caller
38373 disableTooltips : true, // not used yet...
38376 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38377 * @param {String} id The id of the div to use <b>or create</b>
38378 * @param {String} text The text for the tab
38379 * @param {String} content (optional) Content to put in the TabPanelItem body
38380 * @param {Boolean} closable (optional) True to create a close icon on the tab
38381 * @return {Roo.TabPanelItem} The created TabPanelItem
38383 addTab : function(id, text, content, closable, tpl)
38385 var item = new Roo.bootstrap.panel.TabItem({
38389 closable : closable,
38392 this.addTabItem(item);
38394 item.setContent(content);
38400 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38401 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38402 * @return {Roo.TabPanelItem}
38404 getTab : function(id){
38405 return this.items[id];
38409 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38410 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38412 hideTab : function(id){
38413 var t = this.items[id];
38416 this.hiddenCount++;
38417 this.autoSizeTabs();
38422 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38423 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38425 unhideTab : function(id){
38426 var t = this.items[id];
38428 t.setHidden(false);
38429 this.hiddenCount--;
38430 this.autoSizeTabs();
38435 * Adds an existing {@link Roo.TabPanelItem}.
38436 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38438 addTabItem : function(item)
38440 this.items[item.id] = item;
38441 this.items.push(item);
38442 this.autoSizeTabs();
38443 // if(this.resizeTabs){
38444 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38445 // this.autoSizeTabs();
38447 // item.autoSize();
38452 * Removes a {@link Roo.TabPanelItem}.
38453 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38455 removeTab : function(id){
38456 var items = this.items;
38457 var tab = items[id];
38458 if(!tab) { return; }
38459 var index = items.indexOf(tab);
38460 if(this.active == tab && items.length > 1){
38461 var newTab = this.getNextAvailable(index);
38466 this.stripEl.dom.removeChild(tab.pnode.dom);
38467 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38468 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38470 items.splice(index, 1);
38471 delete this.items[tab.id];
38472 tab.fireEvent("close", tab);
38473 tab.purgeListeners();
38474 this.autoSizeTabs();
38477 getNextAvailable : function(start){
38478 var items = this.items;
38480 // look for a next tab that will slide over to
38481 // replace the one being removed
38482 while(index < items.length){
38483 var item = items[++index];
38484 if(item && !item.isHidden()){
38488 // if one isn't found select the previous tab (on the left)
38491 var item = items[--index];
38492 if(item && !item.isHidden()){
38500 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38501 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38503 disableTab : function(id){
38504 var tab = this.items[id];
38505 if(tab && this.active != tab){
38511 * Enables a {@link Roo.TabPanelItem} that is disabled.
38512 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38514 enableTab : function(id){
38515 var tab = this.items[id];
38520 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38521 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38522 * @return {Roo.TabPanelItem} The TabPanelItem.
38524 activate : function(id)
38526 //Roo.log('activite:' + id);
38528 var tab = this.items[id];
38532 if(tab == this.active || tab.disabled){
38536 this.fireEvent("beforetabchange", this, e, tab);
38537 if(e.cancel !== true && !tab.disabled){
38539 this.active.hide();
38541 this.active = this.items[id];
38542 this.active.show();
38543 this.fireEvent("tabchange", this, this.active);
38549 * Gets the active {@link Roo.TabPanelItem}.
38550 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38552 getActiveTab : function(){
38553 return this.active;
38557 * Updates the tab body element to fit the height of the container element
38558 * for overflow scrolling
38559 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38561 syncHeight : function(targetHeight){
38562 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38563 var bm = this.bodyEl.getMargins();
38564 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38565 this.bodyEl.setHeight(newHeight);
38569 onResize : function(){
38570 if(this.monitorResize){
38571 this.autoSizeTabs();
38576 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38578 beginUpdate : function(){
38579 this.updating = true;
38583 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38585 endUpdate : function(){
38586 this.updating = false;
38587 this.autoSizeTabs();
38591 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38593 autoSizeTabs : function()
38595 var count = this.items.length;
38596 var vcount = count - this.hiddenCount;
38599 this.stripEl.hide();
38601 this.stripEl.show();
38604 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38609 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38610 var availWidth = Math.floor(w / vcount);
38611 var b = this.stripBody;
38612 if(b.getWidth() > w){
38613 var tabs = this.items;
38614 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38615 if(availWidth < this.minTabWidth){
38616 /*if(!this.sleft){ // incomplete scrolling code
38617 this.createScrollButtons();
38620 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38623 if(this.currentTabWidth < this.preferredTabWidth){
38624 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38630 * Returns the number of tabs in this TabPanel.
38633 getCount : function(){
38634 return this.items.length;
38638 * Resizes all the tabs to the passed width
38639 * @param {Number} The new width
38641 setTabWidth : function(width){
38642 this.currentTabWidth = width;
38643 for(var i = 0, len = this.items.length; i < len; i++) {
38644 if(!this.items[i].isHidden()) {
38645 this.items[i].setWidth(width);
38651 * Destroys this TabPanel
38652 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38654 destroy : function(removeEl){
38655 Roo.EventManager.removeResizeListener(this.onResize, this);
38656 for(var i = 0, len = this.items.length; i < len; i++){
38657 this.items[i].purgeListeners();
38659 if(removeEl === true){
38660 this.el.update("");
38665 createStrip : function(container)
38667 var strip = document.createElement("nav");
38668 strip.className = Roo.bootstrap.version == 4 ?
38669 "navbar-light bg-light" :
38670 "navbar navbar-default"; //"x-tabs-wrap";
38671 container.appendChild(strip);
38675 createStripList : function(strip)
38677 // div wrapper for retard IE
38678 // returns the "tr" element.
38679 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38680 //'<div class="x-tabs-strip-wrap">'+
38681 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38682 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38683 return strip.firstChild; //.firstChild.firstChild.firstChild;
38685 createBody : function(container)
38687 var body = document.createElement("div");
38688 Roo.id(body, "tab-body");
38689 //Roo.fly(body).addClass("x-tabs-body");
38690 Roo.fly(body).addClass("tab-content");
38691 container.appendChild(body);
38694 createItemBody :function(bodyEl, id){
38695 var body = Roo.getDom(id);
38697 body = document.createElement("div");
38700 //Roo.fly(body).addClass("x-tabs-item-body");
38701 Roo.fly(body).addClass("tab-pane");
38702 bodyEl.insertBefore(body, bodyEl.firstChild);
38706 createStripElements : function(stripEl, text, closable, tpl)
38708 var td = document.createElement("li"); // was td..
38709 td.className = 'nav-item';
38711 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38714 stripEl.appendChild(td);
38716 td.className = "x-tabs-closable";
38717 if(!this.closeTpl){
38718 this.closeTpl = new Roo.Template(
38719 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38720 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38721 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38724 var el = this.closeTpl.overwrite(td, {"text": text});
38725 var close = el.getElementsByTagName("div")[0];
38726 var inner = el.getElementsByTagName("em")[0];
38727 return {"el": el, "close": close, "inner": inner};
38730 // not sure what this is..
38731 // if(!this.tabTpl){
38732 //this.tabTpl = new Roo.Template(
38733 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38734 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38736 // this.tabTpl = new Roo.Template(
38737 // '<a href="#">' +
38738 // '<span unselectable="on"' +
38739 // (this.disableTooltips ? '' : ' title="{text}"') +
38740 // ' >{text}</span></a>'
38746 var template = tpl || this.tabTpl || false;
38749 template = new Roo.Template(
38750 Roo.bootstrap.version == 4 ?
38752 '<a class="nav-link" href="#" unselectable="on"' +
38753 (this.disableTooltips ? '' : ' title="{text}"') +
38756 '<a class="nav-link" href="#">' +
38757 '<span unselectable="on"' +
38758 (this.disableTooltips ? '' : ' title="{text}"') +
38759 ' >{text}</span></a>'
38764 switch (typeof(template)) {
38768 template = new Roo.Template(template);
38774 var el = template.overwrite(td, {"text": text});
38776 var inner = el.getElementsByTagName("span")[0];
38778 return {"el": el, "inner": inner};
38786 * @class Roo.TabPanelItem
38787 * @extends Roo.util.Observable
38788 * Represents an individual item (tab plus body) in a TabPanel.
38789 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38790 * @param {String} id The id of this TabPanelItem
38791 * @param {String} text The text for the tab of this TabPanelItem
38792 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38794 Roo.bootstrap.panel.TabItem = function(config){
38796 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38797 * @type Roo.TabPanel
38799 this.tabPanel = config.panel;
38801 * The id for this TabPanelItem
38804 this.id = config.id;
38806 this.disabled = false;
38808 this.text = config.text;
38810 this.loaded = false;
38811 this.closable = config.closable;
38814 * The body element for this TabPanelItem.
38815 * @type Roo.Element
38817 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38818 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38819 this.bodyEl.setStyle("display", "block");
38820 this.bodyEl.setStyle("zoom", "1");
38821 //this.hideAction();
38823 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38825 this.el = Roo.get(els.el);
38826 this.inner = Roo.get(els.inner, true);
38827 this.textEl = Roo.bootstrap.version == 4 ?
38828 this.el : Roo.get(this.el.dom.firstChild, true);
38830 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38831 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38834 // this.el.on("mousedown", this.onTabMouseDown, this);
38835 this.el.on("click", this.onTabClick, this);
38837 if(config.closable){
38838 var c = Roo.get(els.close, true);
38839 c.dom.title = this.closeText;
38840 c.addClassOnOver("close-over");
38841 c.on("click", this.closeClick, this);
38847 * Fires when this tab becomes the active tab.
38848 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38849 * @param {Roo.TabPanelItem} this
38853 * @event beforeclose
38854 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38855 * @param {Roo.TabPanelItem} this
38856 * @param {Object} e Set cancel to true on this object to cancel the close.
38858 "beforeclose": true,
38861 * Fires when this tab is closed.
38862 * @param {Roo.TabPanelItem} this
38866 * @event deactivate
38867 * Fires when this tab is no longer the active tab.
38868 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38869 * @param {Roo.TabPanelItem} this
38871 "deactivate" : true
38873 this.hidden = false;
38875 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38878 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38880 purgeListeners : function(){
38881 Roo.util.Observable.prototype.purgeListeners.call(this);
38882 this.el.removeAllListeners();
38885 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38888 this.status_node.addClass("active");
38891 this.tabPanel.stripWrap.repaint();
38893 this.fireEvent("activate", this.tabPanel, this);
38897 * Returns true if this tab is the active tab.
38898 * @return {Boolean}
38900 isActive : function(){
38901 return this.tabPanel.getActiveTab() == this;
38905 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38908 this.status_node.removeClass("active");
38910 this.fireEvent("deactivate", this.tabPanel, this);
38913 hideAction : function(){
38914 this.bodyEl.hide();
38915 this.bodyEl.setStyle("position", "absolute");
38916 this.bodyEl.setLeft("-20000px");
38917 this.bodyEl.setTop("-20000px");
38920 showAction : function(){
38921 this.bodyEl.setStyle("position", "relative");
38922 this.bodyEl.setTop("");
38923 this.bodyEl.setLeft("");
38924 this.bodyEl.show();
38928 * Set the tooltip for the tab.
38929 * @param {String} tooltip The tab's tooltip
38931 setTooltip : function(text){
38932 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38933 this.textEl.dom.qtip = text;
38934 this.textEl.dom.removeAttribute('title');
38936 this.textEl.dom.title = text;
38940 onTabClick : function(e){
38941 e.preventDefault();
38942 this.tabPanel.activate(this.id);
38945 onTabMouseDown : function(e){
38946 e.preventDefault();
38947 this.tabPanel.activate(this.id);
38950 getWidth : function(){
38951 return this.inner.getWidth();
38954 setWidth : function(width){
38955 var iwidth = width - this.linode.getPadding("lr");
38956 this.inner.setWidth(iwidth);
38957 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38958 this.linode.setWidth(width);
38962 * Show or hide the tab
38963 * @param {Boolean} hidden True to hide or false to show.
38965 setHidden : function(hidden){
38966 this.hidden = hidden;
38967 this.linode.setStyle("display", hidden ? "none" : "");
38971 * Returns true if this tab is "hidden"
38972 * @return {Boolean}
38974 isHidden : function(){
38975 return this.hidden;
38979 * Returns the text for this tab
38982 getText : function(){
38986 autoSize : function(){
38987 //this.el.beginMeasure();
38988 this.textEl.setWidth(1);
38990 * #2804 [new] Tabs in Roojs
38991 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38993 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38994 //this.el.endMeasure();
38998 * Sets the text for the tab (Note: this also sets the tooltip text)
38999 * @param {String} text The tab's text and tooltip
39001 setText : function(text){
39003 this.textEl.update(text);
39004 this.setTooltip(text);
39005 //if(!this.tabPanel.resizeTabs){
39006 // this.autoSize();
39010 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
39012 activate : function(){
39013 this.tabPanel.activate(this.id);
39017 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
39019 disable : function(){
39020 if(this.tabPanel.active != this){
39021 this.disabled = true;
39022 this.status_node.addClass("disabled");
39027 * Enables this TabPanelItem if it was previously disabled.
39029 enable : function(){
39030 this.disabled = false;
39031 this.status_node.removeClass("disabled");
39035 * Sets the content for this TabPanelItem.
39036 * @param {String} content The content
39037 * @param {Boolean} loadScripts true to look for and load scripts
39039 setContent : function(content, loadScripts){
39040 this.bodyEl.update(content, loadScripts);
39044 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
39045 * @return {Roo.UpdateManager} The UpdateManager
39047 getUpdateManager : function(){
39048 return this.bodyEl.getUpdateManager();
39052 * Set a URL to be used to load the content for this TabPanelItem.
39053 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
39054 * @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)
39055 * @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)
39056 * @return {Roo.UpdateManager} The UpdateManager
39058 setUrl : function(url, params, loadOnce){
39059 if(this.refreshDelegate){
39060 this.un('activate', this.refreshDelegate);
39062 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39063 this.on("activate", this.refreshDelegate);
39064 return this.bodyEl.getUpdateManager();
39068 _handleRefresh : function(url, params, loadOnce){
39069 if(!loadOnce || !this.loaded){
39070 var updater = this.bodyEl.getUpdateManager();
39071 updater.update(url, params, this._setLoaded.createDelegate(this));
39076 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39077 * Will fail silently if the setUrl method has not been called.
39078 * This does not activate the panel, just updates its content.
39080 refresh : function(){
39081 if(this.refreshDelegate){
39082 this.loaded = false;
39083 this.refreshDelegate();
39088 _setLoaded : function(){
39089 this.loaded = true;
39093 closeClick : function(e){
39096 this.fireEvent("beforeclose", this, o);
39097 if(o.cancel !== true){
39098 this.tabPanel.removeTab(this.id);
39102 * The text displayed in the tooltip for the close icon.
39105 closeText : "Close this tab"
39108 * This script refer to:
39109 * Title: International Telephone Input
39110 * Author: Jack O'Connor
39111 * Code version: v12.1.12
39112 * Availability: https://github.com/jackocnr/intl-tel-input.git
39115 Roo.bootstrap.PhoneInputData = function() {
39118 "Afghanistan (افغانستان)",
39123 "Albania (Shqipëri)",
39128 "Algeria (الجزائر)",
39153 "Antigua and Barbuda",
39163 "Armenia (Հայաստան)",
39179 "Austria (Österreich)",
39184 "Azerbaijan (Azərbaycan)",
39194 "Bahrain (البحرين)",
39199 "Bangladesh (বাংলাদেশ)",
39209 "Belarus (Беларусь)",
39214 "Belgium (België)",
39244 "Bosnia and Herzegovina (Босна и Херцеговина)",
39259 "British Indian Ocean Territory",
39264 "British Virgin Islands",
39274 "Bulgaria (България)",
39284 "Burundi (Uburundi)",
39289 "Cambodia (កម្ពុជា)",
39294 "Cameroon (Cameroun)",
39303 ["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"]
39306 "Cape Verde (Kabu Verdi)",
39311 "Caribbean Netherlands",
39322 "Central African Republic (République centrafricaine)",
39342 "Christmas Island",
39348 "Cocos (Keeling) Islands",
39359 "Comoros (جزر القمر)",
39364 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39369 "Congo (Republic) (Congo-Brazzaville)",
39389 "Croatia (Hrvatska)",
39410 "Czech Republic (Česká republika)",
39415 "Denmark (Danmark)",
39430 "Dominican Republic (República Dominicana)",
39434 ["809", "829", "849"]
39452 "Equatorial Guinea (Guinea Ecuatorial)",
39472 "Falkland Islands (Islas Malvinas)",
39477 "Faroe Islands (Føroyar)",
39498 "French Guiana (Guyane française)",
39503 "French Polynesia (Polynésie française)",
39518 "Georgia (საქართველო)",
39523 "Germany (Deutschland)",
39543 "Greenland (Kalaallit Nunaat)",
39580 "Guinea-Bissau (Guiné Bissau)",
39605 "Hungary (Magyarország)",
39610 "Iceland (Ísland)",
39630 "Iraq (العراق)",
39646 "Israel (ישראל)",
39673 "Jordan (الأردن)",
39678 "Kazakhstan (Казахстан)",
39699 "Kuwait (الكويت)",
39704 "Kyrgyzstan (Кыргызстан)",
39714 "Latvia (Latvija)",
39719 "Lebanon (لبنان)",
39734 "Libya (ليبيا)",
39744 "Lithuania (Lietuva)",
39759 "Macedonia (FYROM) (Македонија)",
39764 "Madagascar (Madagasikara)",
39794 "Marshall Islands",
39804 "Mauritania (موريتانيا)",
39809 "Mauritius (Moris)",
39830 "Moldova (Republica Moldova)",
39840 "Mongolia (Монгол)",
39845 "Montenegro (Crna Gora)",
39855 "Morocco (المغرب)",
39861 "Mozambique (Moçambique)",
39866 "Myanmar (Burma) (မြန်မာ)",
39871 "Namibia (Namibië)",
39886 "Netherlands (Nederland)",
39891 "New Caledonia (Nouvelle-Calédonie)",
39926 "North Korea (조선 민주주의 인민 공화국)",
39931 "Northern Mariana Islands",
39947 "Pakistan (پاکستان)",
39957 "Palestine (فلسطين)",
39967 "Papua New Guinea",
40009 "Réunion (La Réunion)",
40015 "Romania (România)",
40031 "Saint Barthélemy",
40042 "Saint Kitts and Nevis",
40052 "Saint Martin (Saint-Martin (partie française))",
40058 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
40063 "Saint Vincent and the Grenadines",
40078 "São Tomé and Príncipe (São Tomé e Príncipe)",
40083 "Saudi Arabia (المملكة العربية السعودية)",
40088 "Senegal (Sénégal)",
40118 "Slovakia (Slovensko)",
40123 "Slovenia (Slovenija)",
40133 "Somalia (Soomaaliya)",
40143 "South Korea (대한민국)",
40148 "South Sudan (جنوب السودان)",
40158 "Sri Lanka (ශ්රී ලංකාව)",
40163 "Sudan (السودان)",
40173 "Svalbard and Jan Mayen",
40184 "Sweden (Sverige)",
40189 "Switzerland (Schweiz)",
40194 "Syria (سوريا)",
40239 "Trinidad and Tobago",
40244 "Tunisia (تونس)",
40249 "Turkey (Türkiye)",
40259 "Turks and Caicos Islands",
40269 "U.S. Virgin Islands",
40279 "Ukraine (Україна)",
40284 "United Arab Emirates (الإمارات العربية المتحدة)",
40306 "Uzbekistan (Oʻzbekiston)",
40316 "Vatican City (Città del Vaticano)",
40327 "Vietnam (Việt Nam)",
40332 "Wallis and Futuna (Wallis-et-Futuna)",
40337 "Western Sahara (الصحراء الغربية)",
40343 "Yemen (اليمن)",
40367 * This script refer to:
40368 * Title: International Telephone Input
40369 * Author: Jack O'Connor
40370 * Code version: v12.1.12
40371 * Availability: https://github.com/jackocnr/intl-tel-input.git
40375 * @class Roo.bootstrap.PhoneInput
40376 * @extends Roo.bootstrap.TriggerField
40377 * An input with International dial-code selection
40379 * @cfg {String} defaultDialCode default '+852'
40380 * @cfg {Array} preferedCountries default []
40383 * Create a new PhoneInput.
40384 * @param {Object} config Configuration options
40387 Roo.bootstrap.PhoneInput = function(config) {
40388 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40391 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40393 listWidth: undefined,
40395 selectedClass: 'active',
40397 invalidClass : "has-warning",
40399 validClass: 'has-success',
40401 allowed: '0123456789',
40406 * @cfg {String} defaultDialCode The default dial code when initializing the input
40408 defaultDialCode: '+852',
40411 * @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
40413 preferedCountries: false,
40415 getAutoCreate : function()
40417 var data = Roo.bootstrap.PhoneInputData();
40418 var align = this.labelAlign || this.parentLabelAlign();
40421 this.allCountries = [];
40422 this.dialCodeMapping = [];
40424 for (var i = 0; i < data.length; i++) {
40426 this.allCountries[i] = {
40430 priority: c[3] || 0,
40431 areaCodes: c[4] || null
40433 this.dialCodeMapping[c[2]] = {
40436 priority: c[3] || 0,
40437 areaCodes: c[4] || null
40449 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40450 maxlength: this.max_length,
40451 cls : 'form-control tel-input',
40452 autocomplete: 'new-password'
40455 var hiddenInput = {
40458 cls: 'hidden-tel-input'
40462 hiddenInput.name = this.name;
40465 if (this.disabled) {
40466 input.disabled = true;
40469 var flag_container = {
40486 cls: this.hasFeedback ? 'has-feedback' : '',
40492 cls: 'dial-code-holder',
40499 cls: 'roo-select2-container input-group',
40506 if (this.fieldLabel.length) {
40509 tooltip: 'This field is required'
40515 cls: 'control-label',
40521 html: this.fieldLabel
40524 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40530 if(this.indicatorpos == 'right') {
40531 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40538 if(align == 'left') {
40546 if(this.labelWidth > 12){
40547 label.style = "width: " + this.labelWidth + 'px';
40549 if(this.labelWidth < 13 && this.labelmd == 0){
40550 this.labelmd = this.labelWidth;
40552 if(this.labellg > 0){
40553 label.cls += ' col-lg-' + this.labellg;
40554 input.cls += ' col-lg-' + (12 - this.labellg);
40556 if(this.labelmd > 0){
40557 label.cls += ' col-md-' + this.labelmd;
40558 container.cls += ' col-md-' + (12 - this.labelmd);
40560 if(this.labelsm > 0){
40561 label.cls += ' col-sm-' + this.labelsm;
40562 container.cls += ' col-sm-' + (12 - this.labelsm);
40564 if(this.labelxs > 0){
40565 label.cls += ' col-xs-' + this.labelxs;
40566 container.cls += ' col-xs-' + (12 - this.labelxs);
40576 var settings = this;
40578 ['xs','sm','md','lg'].map(function(size){
40579 if (settings[size]) {
40580 cfg.cls += ' col-' + size + '-' + settings[size];
40584 this.store = new Roo.data.Store({
40585 proxy : new Roo.data.MemoryProxy({}),
40586 reader : new Roo.data.JsonReader({
40597 'name' : 'dialCode',
40601 'name' : 'priority',
40605 'name' : 'areaCodes',
40612 if(!this.preferedCountries) {
40613 this.preferedCountries = [
40620 var p = this.preferedCountries.reverse();
40623 for (var i = 0; i < p.length; i++) {
40624 for (var j = 0; j < this.allCountries.length; j++) {
40625 if(this.allCountries[j].iso2 == p[i]) {
40626 var t = this.allCountries[j];
40627 this.allCountries.splice(j,1);
40628 this.allCountries.unshift(t);
40634 this.store.proxy.data = {
40636 data: this.allCountries
40642 initEvents : function()
40645 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40647 this.indicator = this.indicatorEl();
40648 this.flag = this.flagEl();
40649 this.dialCodeHolder = this.dialCodeHolderEl();
40651 this.trigger = this.el.select('div.flag-box',true).first();
40652 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40657 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40658 _this.list.setWidth(lw);
40661 this.list.on('mouseover', this.onViewOver, this);
40662 this.list.on('mousemove', this.onViewMove, this);
40663 this.inputEl().on("keyup", this.onKeyUp, this);
40664 this.inputEl().on("keypress", this.onKeyPress, this);
40666 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40668 this.view = new Roo.View(this.list, this.tpl, {
40669 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40672 this.view.on('click', this.onViewClick, this);
40673 this.setValue(this.defaultDialCode);
40676 onTriggerClick : function(e)
40678 Roo.log('trigger click');
40683 if(this.isExpanded()){
40685 this.hasFocus = false;
40687 this.store.load({});
40688 this.hasFocus = true;
40693 isExpanded : function()
40695 return this.list.isVisible();
40698 collapse : function()
40700 if(!this.isExpanded()){
40704 Roo.get(document).un('mousedown', this.collapseIf, this);
40705 Roo.get(document).un('mousewheel', this.collapseIf, this);
40706 this.fireEvent('collapse', this);
40710 expand : function()
40714 if(this.isExpanded() || !this.hasFocus){
40718 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40719 this.list.setWidth(lw);
40722 this.restrictHeight();
40724 Roo.get(document).on('mousedown', this.collapseIf, this);
40725 Roo.get(document).on('mousewheel', this.collapseIf, this);
40727 this.fireEvent('expand', this);
40730 restrictHeight : function()
40732 this.list.alignTo(this.inputEl(), this.listAlign);
40733 this.list.alignTo(this.inputEl(), this.listAlign);
40736 onViewOver : function(e, t)
40738 if(this.inKeyMode){
40741 var item = this.view.findItemFromChild(t);
40744 var index = this.view.indexOf(item);
40745 this.select(index, false);
40750 onViewClick : function(view, doFocus, el, e)
40752 var index = this.view.getSelectedIndexes()[0];
40754 var r = this.store.getAt(index);
40757 this.onSelect(r, index);
40759 if(doFocus !== false && !this.blockFocus){
40760 this.inputEl().focus();
40764 onViewMove : function(e, t)
40766 this.inKeyMode = false;
40769 select : function(index, scrollIntoView)
40771 this.selectedIndex = index;
40772 this.view.select(index);
40773 if(scrollIntoView !== false){
40774 var el = this.view.getNode(index);
40776 this.list.scrollChildIntoView(el, false);
40781 createList : function()
40783 this.list = Roo.get(document.body).createChild({
40785 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40786 style: 'display:none'
40789 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40792 collapseIf : function(e)
40794 var in_combo = e.within(this.el);
40795 var in_list = e.within(this.list);
40796 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40798 if (in_combo || in_list || is_list) {
40804 onSelect : function(record, index)
40806 if(this.fireEvent('beforeselect', this, record, index) !== false){
40808 this.setFlagClass(record.data.iso2);
40809 this.setDialCode(record.data.dialCode);
40810 this.hasFocus = false;
40812 this.fireEvent('select', this, record, index);
40816 flagEl : function()
40818 var flag = this.el.select('div.flag',true).first();
40825 dialCodeHolderEl : function()
40827 var d = this.el.select('input.dial-code-holder',true).first();
40834 setDialCode : function(v)
40836 this.dialCodeHolder.dom.value = '+'+v;
40839 setFlagClass : function(n)
40841 this.flag.dom.className = 'flag '+n;
40844 getValue : function()
40846 var v = this.inputEl().getValue();
40847 if(this.dialCodeHolder) {
40848 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40853 setValue : function(v)
40855 var d = this.getDialCode(v);
40857 //invalid dial code
40858 if(v.length == 0 || !d || d.length == 0) {
40860 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40861 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40867 this.setFlagClass(this.dialCodeMapping[d].iso2);
40868 this.setDialCode(d);
40869 this.inputEl().dom.value = v.replace('+'+d,'');
40870 this.hiddenEl().dom.value = this.getValue();
40875 getDialCode : function(v)
40879 if (v.length == 0) {
40880 return this.dialCodeHolder.dom.value;
40884 if (v.charAt(0) != "+") {
40887 var numericChars = "";
40888 for (var i = 1; i < v.length; i++) {
40889 var c = v.charAt(i);
40892 if (this.dialCodeMapping[numericChars]) {
40893 dialCode = v.substr(1, i);
40895 if (numericChars.length == 4) {
40905 this.setValue(this.defaultDialCode);
40909 hiddenEl : function()
40911 return this.el.select('input.hidden-tel-input',true).first();
40914 // after setting val
40915 onKeyUp : function(e){
40916 this.setValue(this.getValue());
40919 onKeyPress : function(e){
40920 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40927 * @class Roo.bootstrap.MoneyField
40928 * @extends Roo.bootstrap.ComboBox
40929 * Bootstrap MoneyField class
40932 * Create a new MoneyField.
40933 * @param {Object} config Configuration options
40936 Roo.bootstrap.MoneyField = function(config) {
40938 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40942 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40945 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40947 allowDecimals : true,
40949 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40951 decimalSeparator : ".",
40953 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40955 decimalPrecision : 0,
40957 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40959 allowNegative : true,
40961 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40965 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40967 minValue : Number.NEGATIVE_INFINITY,
40969 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40971 maxValue : Number.MAX_VALUE,
40973 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40975 minText : "The minimum value for this field is {0}",
40977 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40979 maxText : "The maximum value for this field is {0}",
40981 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40982 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40984 nanText : "{0} is not a valid number",
40986 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40990 * @cfg {String} defaults currency of the MoneyField
40991 * value should be in lkey
40993 defaultCurrency : false,
40995 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40997 thousandsDelimiter : false,
40999 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
41010 getAutoCreate : function()
41012 var align = this.labelAlign || this.parentLabelAlign();
41024 cls : 'form-control roo-money-amount-input',
41025 autocomplete: 'new-password'
41028 var hiddenInput = {
41032 cls: 'hidden-number-input'
41035 if(this.max_length) {
41036 input.maxlength = this.max_length;
41040 hiddenInput.name = this.name;
41043 if (this.disabled) {
41044 input.disabled = true;
41047 var clg = 12 - this.inputlg;
41048 var cmd = 12 - this.inputmd;
41049 var csm = 12 - this.inputsm;
41050 var cxs = 12 - this.inputxs;
41054 cls : 'row roo-money-field',
41058 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
41062 cls: 'roo-select2-container input-group',
41066 cls : 'form-control roo-money-currency-input',
41067 autocomplete: 'new-password',
41069 name : this.currencyName
41073 cls : 'input-group-addon',
41087 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41091 cls: this.hasFeedback ? 'has-feedback' : '',
41102 if (this.fieldLabel.length) {
41105 tooltip: 'This field is required'
41111 cls: 'control-label',
41117 html: this.fieldLabel
41120 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41126 if(this.indicatorpos == 'right') {
41127 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41134 if(align == 'left') {
41142 if(this.labelWidth > 12){
41143 label.style = "width: " + this.labelWidth + 'px';
41145 if(this.labelWidth < 13 && this.labelmd == 0){
41146 this.labelmd = this.labelWidth;
41148 if(this.labellg > 0){
41149 label.cls += ' col-lg-' + this.labellg;
41150 input.cls += ' col-lg-' + (12 - this.labellg);
41152 if(this.labelmd > 0){
41153 label.cls += ' col-md-' + this.labelmd;
41154 container.cls += ' col-md-' + (12 - this.labelmd);
41156 if(this.labelsm > 0){
41157 label.cls += ' col-sm-' + this.labelsm;
41158 container.cls += ' col-sm-' + (12 - this.labelsm);
41160 if(this.labelxs > 0){
41161 label.cls += ' col-xs-' + this.labelxs;
41162 container.cls += ' col-xs-' + (12 - this.labelxs);
41173 var settings = this;
41175 ['xs','sm','md','lg'].map(function(size){
41176 if (settings[size]) {
41177 cfg.cls += ' col-' + size + '-' + settings[size];
41184 initEvents : function()
41186 this.indicator = this.indicatorEl();
41188 this.initCurrencyEvent();
41190 this.initNumberEvent();
41193 initCurrencyEvent : function()
41196 throw "can not find store for combo";
41199 this.store = Roo.factory(this.store, Roo.data);
41200 this.store.parent = this;
41204 this.triggerEl = this.el.select('.input-group-addon', true).first();
41206 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41211 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41212 _this.list.setWidth(lw);
41215 this.list.on('mouseover', this.onViewOver, this);
41216 this.list.on('mousemove', this.onViewMove, this);
41217 this.list.on('scroll', this.onViewScroll, this);
41220 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41223 this.view = new Roo.View(this.list, this.tpl, {
41224 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41227 this.view.on('click', this.onViewClick, this);
41229 this.store.on('beforeload', this.onBeforeLoad, this);
41230 this.store.on('load', this.onLoad, this);
41231 this.store.on('loadexception', this.onLoadException, this);
41233 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41234 "up" : function(e){
41235 this.inKeyMode = true;
41239 "down" : function(e){
41240 if(!this.isExpanded()){
41241 this.onTriggerClick();
41243 this.inKeyMode = true;
41248 "enter" : function(e){
41251 if(this.fireEvent("specialkey", this, e)){
41252 this.onViewClick(false);
41258 "esc" : function(e){
41262 "tab" : function(e){
41265 if(this.fireEvent("specialkey", this, e)){
41266 this.onViewClick(false);
41274 doRelay : function(foo, bar, hname){
41275 if(hname == 'down' || this.scope.isExpanded()){
41276 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41284 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41288 initNumberEvent : function(e)
41290 this.inputEl().on("keydown" , this.fireKey, this);
41291 this.inputEl().on("focus", this.onFocus, this);
41292 this.inputEl().on("blur", this.onBlur, this);
41294 this.inputEl().relayEvent('keyup', this);
41296 if(this.indicator){
41297 this.indicator.addClass('invisible');
41300 this.originalValue = this.getValue();
41302 if(this.validationEvent == 'keyup'){
41303 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41304 this.inputEl().on('keyup', this.filterValidation, this);
41306 else if(this.validationEvent !== false){
41307 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41310 if(this.selectOnFocus){
41311 this.on("focus", this.preFocus, this);
41314 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41315 this.inputEl().on("keypress", this.filterKeys, this);
41317 this.inputEl().relayEvent('keypress', this);
41320 var allowed = "0123456789";
41322 if(this.allowDecimals){
41323 allowed += this.decimalSeparator;
41326 if(this.allowNegative){
41330 if(this.thousandsDelimiter) {
41334 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41336 var keyPress = function(e){
41338 var k = e.getKey();
41340 var c = e.getCharCode();
41343 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41344 allowed.indexOf(String.fromCharCode(c)) === -1
41350 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41354 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41359 this.inputEl().on("keypress", keyPress, this);
41363 onTriggerClick : function(e)
41370 this.loadNext = false;
41372 if(this.isExpanded()){
41377 this.hasFocus = true;
41379 if(this.triggerAction == 'all') {
41380 this.doQuery(this.allQuery, true);
41384 this.doQuery(this.getRawValue());
41387 getCurrency : function()
41389 var v = this.currencyEl().getValue();
41394 restrictHeight : function()
41396 this.list.alignTo(this.currencyEl(), this.listAlign);
41397 this.list.alignTo(this.currencyEl(), this.listAlign);
41400 onViewClick : function(view, doFocus, el, e)
41402 var index = this.view.getSelectedIndexes()[0];
41404 var r = this.store.getAt(index);
41407 this.onSelect(r, index);
41411 onSelect : function(record, index){
41413 if(this.fireEvent('beforeselect', this, record, index) !== false){
41415 this.setFromCurrencyData(index > -1 ? record.data : false);
41419 this.fireEvent('select', this, record, index);
41423 setFromCurrencyData : function(o)
41427 this.lastCurrency = o;
41429 if (this.currencyField) {
41430 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41432 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41435 this.lastSelectionText = currency;
41437 //setting default currency
41438 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41439 this.setCurrency(this.defaultCurrency);
41443 this.setCurrency(currency);
41446 setFromData : function(o)
41450 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41452 this.setFromCurrencyData(c);
41457 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41459 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41462 this.setValue(value);
41466 setCurrency : function(v)
41468 this.currencyValue = v;
41471 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41476 setValue : function(v)
41478 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41484 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41486 this.inputEl().dom.value = (v == '') ? '' :
41487 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41489 if(!this.allowZero && v === '0') {
41490 this.hiddenEl().dom.value = '';
41491 this.inputEl().dom.value = '';
41498 getRawValue : function()
41500 var v = this.inputEl().getValue();
41505 getValue : function()
41507 return this.fixPrecision(this.parseValue(this.getRawValue()));
41510 parseValue : function(value)
41512 if(this.thousandsDelimiter) {
41514 r = new RegExp(",", "g");
41515 value = value.replace(r, "");
41518 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41519 return isNaN(value) ? '' : value;
41523 fixPrecision : function(value)
41525 if(this.thousandsDelimiter) {
41527 r = new RegExp(",", "g");
41528 value = value.replace(r, "");
41531 var nan = isNaN(value);
41533 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41534 return nan ? '' : value;
41536 return parseFloat(value).toFixed(this.decimalPrecision);
41539 decimalPrecisionFcn : function(v)
41541 return Math.floor(v);
41544 validateValue : function(value)
41546 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41550 var num = this.parseValue(value);
41553 this.markInvalid(String.format(this.nanText, value));
41557 if(num < this.minValue){
41558 this.markInvalid(String.format(this.minText, this.minValue));
41562 if(num > this.maxValue){
41563 this.markInvalid(String.format(this.maxText, this.maxValue));
41570 validate : function()
41572 if(this.disabled || this.allowBlank){
41577 var currency = this.getCurrency();
41579 if(this.validateValue(this.getRawValue()) && currency.length){
41584 this.markInvalid();
41588 getName: function()
41593 beforeBlur : function()
41599 var v = this.parseValue(this.getRawValue());
41606 onBlur : function()
41610 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41611 //this.el.removeClass(this.focusClass);
41614 this.hasFocus = false;
41616 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41620 var v = this.getValue();
41622 if(String(v) !== String(this.startValue)){
41623 this.fireEvent('change', this, v, this.startValue);
41626 this.fireEvent("blur", this);
41629 inputEl : function()
41631 return this.el.select('.roo-money-amount-input', true).first();
41634 currencyEl : function()
41636 return this.el.select('.roo-money-currency-input', true).first();
41639 hiddenEl : function()
41641 return this.el.select('input.hidden-number-input',true).first();
41645 * @class Roo.bootstrap.BezierSignature
41646 * @extends Roo.bootstrap.Component
41647 * Bootstrap BezierSignature class
41648 * This script refer to:
41649 * Title: Signature Pad
41651 * Availability: https://github.com/szimek/signature_pad
41654 * Create a new BezierSignature
41655 * @param {Object} config The config object
41658 Roo.bootstrap.BezierSignature = function(config){
41659 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41665 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41672 mouse_btn_down: true,
41675 * @cfg {int} canvas height
41677 canvas_height: '200px',
41680 * @cfg {float|function} Radius of a single dot.
41685 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41690 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41695 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41700 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41705 * @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.
41707 bg_color: 'rgba(0, 0, 0, 0)',
41710 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41712 dot_color: 'black',
41715 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41717 velocity_filter_weight: 0.7,
41720 * @cfg {function} Callback when stroke begin.
41725 * @cfg {function} Callback when stroke end.
41729 getAutoCreate : function()
41731 var cls = 'roo-signature column';
41734 cls += ' ' + this.cls;
41744 for(var i = 0; i < col_sizes.length; i++) {
41745 if(this[col_sizes[i]]) {
41746 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41756 cls: 'roo-signature-body',
41760 cls: 'roo-signature-body-canvas',
41761 height: this.canvas_height,
41762 width: this.canvas_width
41769 style: 'display: none'
41777 initEvents: function()
41779 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41781 var canvas = this.canvasEl();
41783 // mouse && touch event swapping...
41784 canvas.dom.style.touchAction = 'none';
41785 canvas.dom.style.msTouchAction = 'none';
41787 this.mouse_btn_down = false;
41788 canvas.on('mousedown', this._handleMouseDown, this);
41789 canvas.on('mousemove', this._handleMouseMove, this);
41790 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41792 if (window.PointerEvent) {
41793 canvas.on('pointerdown', this._handleMouseDown, this);
41794 canvas.on('pointermove', this._handleMouseMove, this);
41795 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41798 if ('ontouchstart' in window) {
41799 canvas.on('touchstart', this._handleTouchStart, this);
41800 canvas.on('touchmove', this._handleTouchMove, this);
41801 canvas.on('touchend', this._handleTouchEnd, this);
41804 Roo.EventManager.onWindowResize(this.resize, this, true);
41806 // file input event
41807 this.fileEl().on('change', this.uploadImage, this);
41814 resize: function(){
41816 var canvas = this.canvasEl().dom;
41817 var ctx = this.canvasElCtx();
41818 var img_data = false;
41820 if(canvas.width > 0) {
41821 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41823 // setting canvas width will clean img data
41826 var style = window.getComputedStyle ?
41827 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41829 var padding_left = parseInt(style.paddingLeft) || 0;
41830 var padding_right = parseInt(style.paddingRight) || 0;
41832 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41835 ctx.putImageData(img_data, 0, 0);
41839 _handleMouseDown: function(e)
41841 if (e.browserEvent.which === 1) {
41842 this.mouse_btn_down = true;
41843 this.strokeBegin(e);
41847 _handleMouseMove: function (e)
41849 if (this.mouse_btn_down) {
41850 this.strokeMoveUpdate(e);
41854 _handleMouseUp: function (e)
41856 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41857 this.mouse_btn_down = false;
41862 _handleTouchStart: function (e) {
41864 e.preventDefault();
41865 if (e.browserEvent.targetTouches.length === 1) {
41866 // var touch = e.browserEvent.changedTouches[0];
41867 // this.strokeBegin(touch);
41869 this.strokeBegin(e); // assume e catching the correct xy...
41873 _handleTouchMove: function (e) {
41874 e.preventDefault();
41875 // var touch = event.targetTouches[0];
41876 // _this._strokeMoveUpdate(touch);
41877 this.strokeMoveUpdate(e);
41880 _handleTouchEnd: function (e) {
41881 var wasCanvasTouched = e.target === this.canvasEl().dom;
41882 if (wasCanvasTouched) {
41883 e.preventDefault();
41884 // var touch = event.changedTouches[0];
41885 // _this._strokeEnd(touch);
41890 reset: function () {
41891 this._lastPoints = [];
41892 this._lastVelocity = 0;
41893 this._lastWidth = (this.min_width + this.max_width) / 2;
41894 this.canvasElCtx().fillStyle = this.dot_color;
41897 strokeMoveUpdate: function(e)
41899 this.strokeUpdate(e);
41901 if (this.throttle) {
41902 this.throttleStroke(this.strokeUpdate, this.throttle);
41905 this.strokeUpdate(e);
41909 strokeBegin: function(e)
41911 var newPointGroup = {
41912 color: this.dot_color,
41916 if (typeof this.onBegin === 'function') {
41920 this.curve_data.push(newPointGroup);
41922 this.strokeUpdate(e);
41925 strokeUpdate: function(e)
41927 var rect = this.canvasEl().dom.getBoundingClientRect();
41928 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41929 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41930 var lastPoints = lastPointGroup.points;
41931 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41932 var isLastPointTooClose = lastPoint
41933 ? point.distanceTo(lastPoint) <= this.min_distance
41935 var color = lastPointGroup.color;
41936 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41937 var curve = this.addPoint(point);
41939 this.drawDot({color: color, point: point});
41942 this.drawCurve({color: color, curve: curve});
41952 strokeEnd: function(e)
41954 this.strokeUpdate(e);
41955 if (typeof this.onEnd === 'function') {
41960 addPoint: function (point) {
41961 var _lastPoints = this._lastPoints;
41962 _lastPoints.push(point);
41963 if (_lastPoints.length > 2) {
41964 if (_lastPoints.length === 3) {
41965 _lastPoints.unshift(_lastPoints[0]);
41967 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41968 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41969 _lastPoints.shift();
41975 calculateCurveWidths: function (startPoint, endPoint) {
41976 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41977 (1 - this.velocity_filter_weight) * this._lastVelocity;
41979 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41982 start: this._lastWidth
41985 this._lastVelocity = velocity;
41986 this._lastWidth = newWidth;
41990 drawDot: function (_a) {
41991 var color = _a.color, point = _a.point;
41992 var ctx = this.canvasElCtx();
41993 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41995 this.drawCurveSegment(point.x, point.y, width);
41997 ctx.fillStyle = color;
42001 drawCurve: function (_a) {
42002 var color = _a.color, curve = _a.curve;
42003 var ctx = this.canvasElCtx();
42004 var widthDelta = curve.endWidth - curve.startWidth;
42005 var drawSteps = Math.floor(curve.length()) * 2;
42007 ctx.fillStyle = color;
42008 for (var i = 0; i < drawSteps; i += 1) {
42009 var t = i / drawSteps;
42015 var x = uuu * curve.startPoint.x;
42016 x += 3 * uu * t * curve.control1.x;
42017 x += 3 * u * tt * curve.control2.x;
42018 x += ttt * curve.endPoint.x;
42019 var y = uuu * curve.startPoint.y;
42020 y += 3 * uu * t * curve.control1.y;
42021 y += 3 * u * tt * curve.control2.y;
42022 y += ttt * curve.endPoint.y;
42023 var width = curve.startWidth + ttt * widthDelta;
42024 this.drawCurveSegment(x, y, width);
42030 drawCurveSegment: function (x, y, width) {
42031 var ctx = this.canvasElCtx();
42033 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
42034 this.is_empty = false;
42039 var ctx = this.canvasElCtx();
42040 var canvas = this.canvasEl().dom;
42041 ctx.fillStyle = this.bg_color;
42042 ctx.clearRect(0, 0, canvas.width, canvas.height);
42043 ctx.fillRect(0, 0, canvas.width, canvas.height);
42044 this.curve_data = [];
42046 this.is_empty = true;
42051 return this.el.select('input',true).first();
42054 canvasEl: function()
42056 return this.el.select('canvas',true).first();
42059 canvasElCtx: function()
42061 return this.el.select('canvas',true).first().dom.getContext('2d');
42064 getImage: function(type)
42066 if(this.is_empty) {
42071 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42074 drawFromImage: function(img_src)
42076 var img = new Image();
42078 img.onload = function(){
42079 this.canvasElCtx().drawImage(img, 0, 0);
42084 this.is_empty = false;
42087 selectImage: function()
42089 this.fileEl().dom.click();
42092 uploadImage: function(e)
42094 var reader = new FileReader();
42096 reader.onload = function(e){
42097 var img = new Image();
42098 img.onload = function(){
42100 this.canvasElCtx().drawImage(img, 0, 0);
42102 img.src = e.target.result;
42105 reader.readAsDataURL(e.target.files[0]);
42108 // Bezier Point Constructor
42109 Point: (function () {
42110 function Point(x, y, time) {
42113 this.time = time || Date.now();
42115 Point.prototype.distanceTo = function (start) {
42116 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42118 Point.prototype.equals = function (other) {
42119 return this.x === other.x && this.y === other.y && this.time === other.time;
42121 Point.prototype.velocityFrom = function (start) {
42122 return this.time !== start.time
42123 ? this.distanceTo(start) / (this.time - start.time)
42130 // Bezier Constructor
42131 Bezier: (function () {
42132 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42133 this.startPoint = startPoint;
42134 this.control2 = control2;
42135 this.control1 = control1;
42136 this.endPoint = endPoint;
42137 this.startWidth = startWidth;
42138 this.endWidth = endWidth;
42140 Bezier.fromPoints = function (points, widths, scope) {
42141 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42142 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42143 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42145 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42146 var dx1 = s1.x - s2.x;
42147 var dy1 = s1.y - s2.y;
42148 var dx2 = s2.x - s3.x;
42149 var dy2 = s2.y - s3.y;
42150 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42151 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42152 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42153 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42154 var dxm = m1.x - m2.x;
42155 var dym = m1.y - m2.y;
42156 var k = l2 / (l1 + l2);
42157 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42158 var tx = s2.x - cm.x;
42159 var ty = s2.y - cm.y;
42161 c1: new scope.Point(m1.x + tx, m1.y + ty),
42162 c2: new scope.Point(m2.x + tx, m2.y + ty)
42165 Bezier.prototype.length = function () {
42170 for (var i = 0; i <= steps; i += 1) {
42172 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42173 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42175 var xdiff = cx - px;
42176 var ydiff = cy - py;
42177 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42184 Bezier.prototype.point = function (t, start, c1, c2, end) {
42185 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42186 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42187 + (3.0 * c2 * (1.0 - t) * t * t)
42188 + (end * t * t * t);
42193 throttleStroke: function(fn, wait) {
42194 if (wait === void 0) { wait = 250; }
42196 var timeout = null;
42200 var later = function () {
42201 previous = Date.now();
42203 result = fn.apply(storedContext, storedArgs);
42205 storedContext = null;
42209 return function wrapper() {
42211 for (var _i = 0; _i < arguments.length; _i++) {
42212 args[_i] = arguments[_i];
42214 var now = Date.now();
42215 var remaining = wait - (now - previous);
42216 storedContext = this;
42218 if (remaining <= 0 || remaining > wait) {
42220 clearTimeout(timeout);
42224 result = fn.apply(storedContext, storedArgs);
42226 storedContext = null;
42230 else if (!timeout) {
42231 timeout = window.setTimeout(later, remaining);