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/)) {
17 * Ext JS Library 1.1.1
18 * Copyright(c) 2006-2007, Ext JS, LLC.
20 * Originally Released Under LGPL - original licence link has changed is not relivant.
23 * <script type="text/javascript">
29 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
30 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
31 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
34 * @param {Object} config The config object
36 Roo.Shadow = function(config){
37 Roo.apply(this, config);
38 if(typeof this.mode != "string"){
39 this.mode = this.defaultMode;
41 var o = this.offset, a = {h: 0};
42 var rad = Math.floor(this.offset/2);
43 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
49 a.l -= this.offset + rad;
50 a.t -= this.offset + rad;
61 a.l -= (this.offset - rad);
62 a.t -= this.offset + rad;
64 a.w -= (this.offset - rad)*2;
75 a.l -= (this.offset - rad);
76 a.t -= (this.offset - rad);
78 a.w -= (this.offset + rad + 1);
79 a.h -= (this.offset + rad);
88 Roo.Shadow.prototype = {
91 * The shadow display mode. Supports the following options:<br />
92 * sides: Shadow displays on both sides and bottom only<br />
93 * frame: Shadow displays equally on all four sides<br />
94 * drop: Traditional bottom-right drop shadow (default)
97 * @cfg {String} offset
98 * The number of pixels to offset the shadow from the element (defaults to 4)
106 * Displays the shadow under the target element
107 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
109 show : function(target){
110 target = Roo.get(target);
112 this.el = Roo.Shadow.Pool.pull();
113 if(this.el.dom.nextSibling != target.dom){
114 this.el.insertBefore(target);
117 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
119 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
122 target.getLeft(true),
127 this.el.dom.style.display = "block";
131 * Returns true if the shadow is visible, else false
133 isVisible : function(){
134 return this.el ? true : false;
138 * Direct alignment when values are already available. Show must be called at least once before
139 * calling this method to ensure it is initialized.
140 * @param {Number} left The target element left position
141 * @param {Number} top The target element top position
142 * @param {Number} width The target element width
143 * @param {Number} height The target element height
145 realign : function(l, t, w, h){
149 var a = this.adjusts, d = this.el.dom, s = d.style;
151 s.left = (l+a.l)+"px";
152 s.top = (t+a.t)+"px";
153 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
155 if(s.width != sws || s.height != shs){
159 var cn = d.childNodes;
160 var sww = Math.max(0, (sw-12))+"px";
161 cn[0].childNodes[1].style.width = sww;
162 cn[1].childNodes[1].style.width = sww;
163 cn[2].childNodes[1].style.width = sww;
164 cn[1].style.height = Math.max(0, (sh-12))+"px";
174 this.el.dom.style.display = "none";
175 Roo.Shadow.Pool.push(this.el);
181 * Adjust the z-index of this shadow
182 * @param {Number} zindex The new z-index
184 setZIndex : function(z){
187 this.el.setStyle("z-index", z);
192 // Private utility class that manages the internal Shadow cache
193 Roo.Shadow.Pool = function(){
195 var markup = Roo.isIE ?
196 '<div class="x-ie-shadow"></div>' :
197 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
202 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
203 sh.autoBoxAdjust = false;
215 * base class for bootstrap elements.
219 Roo.bootstrap = Roo.bootstrap || {};
221 * @class Roo.bootstrap.Component
222 * @extends Roo.Component
223 * Bootstrap Component base class
224 * @cfg {String} cls css class
225 * @cfg {String} style any extra css
226 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
227 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
228 * @cfg {string} dataId cutomer id
229 * @cfg {string} name Specifies name attribute
230 * @cfg {string} tooltip Text for the tooltip
231 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
232 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
235 * Do not use directly - it does not do anything..
236 * @param {Object} config The config object
241 Roo.bootstrap.Component = function(config){
242 Roo.bootstrap.Component.superclass.constructor.call(this, config);
246 * @event childrenrendered
247 * Fires when the children have been rendered..
248 * @param {Roo.bootstrap.Component} this
250 "childrenrendered" : true
259 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
262 allowDomMove : false, // to stop relocations in parent onRender...
272 * Initialize Events for the element
274 initEvents : function() { },
280 can_build_overlaid : true,
282 container_method : false,
289 // returns the parent component..
290 return Roo.ComponentMgr.get(this.parentId)
296 onRender : function(ct, position)
298 // Roo.log("Call onRender: " + this.xtype);
300 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
303 if (this.el.attr('xtype')) {
304 this.el.attr('xtypex', this.el.attr('xtype'));
305 this.el.dom.removeAttribute('xtype');
315 var cfg = Roo.apply({}, this.getAutoCreate());
317 cfg.id = this.id || Roo.id();
319 // fill in the extra attributes
320 if (this.xattr && typeof(this.xattr) =='object') {
321 for (var i in this.xattr) {
322 cfg[i] = this.xattr[i];
327 cfg.dataId = this.dataId;
331 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
334 if (this.style) { // fixme needs to support more complex style data.
335 cfg.style = this.style;
339 cfg.name = this.name;
342 this.el = ct.createChild(cfg, position);
345 this.tooltipEl().attr('tooltip', this.tooltip);
348 if(this.tabIndex !== undefined){
349 this.el.dom.setAttribute('tabIndex', this.tabIndex);
356 * Fetch the element to add children to
357 * @return {Roo.Element} defaults to this.el
359 getChildContainer : function()
364 * Fetch the element to display the tooltip on.
365 * @return {Roo.Element} defaults to this.el
367 tooltipEl : function()
372 addxtype : function(tree,cntr)
376 cn = Roo.factory(tree);
377 //Roo.log(['addxtype', cn]);
379 cn.parentType = this.xtype; //??
380 cn.parentId = this.id;
382 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
383 if (typeof(cn.container_method) == 'string') {
384 cntr = cn.container_method;
388 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
390 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
392 var build_from_html = Roo.XComponent.build_from_html;
394 var is_body = (tree.xtype == 'Body') ;
396 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
398 var self_cntr_el = Roo.get(this[cntr](false));
400 // do not try and build conditional elements
401 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
405 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
406 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
407 return this.addxtypeChild(tree,cntr, is_body);
410 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
413 return this.addxtypeChild(Roo.apply({}, tree),cntr);
416 Roo.log('skipping render');
422 if (!build_from_html) {
426 // this i think handles overlaying multiple children of the same type
427 // with the sam eelement.. - which might be buggy..
429 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
435 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
439 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
446 addxtypeChild : function (tree, cntr, is_body)
448 Roo.debug && Roo.log('addxtypeChild:' + cntr);
450 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
453 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
454 (typeof(tree['flexy:foreach']) != 'undefined');
458 skip_children = false;
459 // render the element if it's not BODY.
462 // if parent was disabled, then do not try and create the children..
463 if(!this[cntr](true)){
468 cn = Roo.factory(tree);
470 cn.parentType = this.xtype; //??
471 cn.parentId = this.id;
473 var build_from_html = Roo.XComponent.build_from_html;
476 // does the container contain child eleemnts with 'xtype' attributes.
477 // that match this xtype..
478 // note - when we render we create these as well..
479 // so we should check to see if body has xtype set.
480 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
482 var self_cntr_el = Roo.get(this[cntr](false));
483 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
485 //Roo.log(Roo.XComponent.build_from_html);
486 //Roo.log("got echild:");
489 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
490 // and are not displayed -this causes this to use up the wrong element when matching.
491 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
494 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
495 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
501 //echild.dom.removeAttribute('xtype');
503 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
504 Roo.debug && Roo.log(self_cntr_el);
505 Roo.debug && Roo.log(echild);
506 Roo.debug && Roo.log(cn);
512 // if object has flexy:if - then it may or may not be rendered.
513 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
514 // skip a flexy if element.
515 Roo.debug && Roo.log('skipping render');
516 Roo.debug && Roo.log(tree);
518 Roo.debug && Roo.log('skipping all children');
519 skip_children = true;
524 // actually if flexy:foreach is found, we really want to create
525 // multiple copies here...
527 //Roo.log(this[cntr]());
528 // some elements do not have render methods.. like the layouts...
530 if(this[cntr](true) === false){
535 cn.render && cn.render(this[cntr](true));
538 // then add the element..
545 if (typeof (tree.menu) != 'undefined') {
546 tree.menu.parentType = cn.xtype;
547 tree.menu.triggerEl = cn.el;
548 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
552 if (!tree.items || !tree.items.length) {
554 //Roo.log(["no children", this]);
559 var items = tree.items;
562 //Roo.log(items.length);
564 if (!skip_children) {
565 for(var i =0;i < items.length;i++) {
566 // Roo.log(['add child', items[i]]);
567 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
573 //Roo.log("fire childrenrendered");
575 cn.fireEvent('childrenrendered', this);
581 * Set the element that will be used to show or hide
583 setVisibilityEl : function(el)
585 this.visibilityEl = el;
589 * Get the element that will be used to show or hide
591 getVisibilityEl : function()
593 if (typeof(this.visibilityEl) == 'object') {
594 return this.visibilityEl;
597 if (typeof(this.visibilityEl) == 'string') {
598 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
605 * Show a component - removes 'hidden' class
609 if(!this.getVisibilityEl()){
613 this.getVisibilityEl().removeClass(['hidden','d-none']);
615 this.fireEvent('show', this);
620 * Hide a component - adds 'hidden' class
624 if(!this.getVisibilityEl()){
628 this.getVisibilityEl().addClass(['hidden','d-none']);
630 this.fireEvent('hide', this);
643 * @class Roo.bootstrap.Element
644 * @extends Roo.bootstrap.Component
645 * Bootstrap Element class
646 * @cfg {String} html contents of the element
647 * @cfg {String} tag tag of the element
648 * @cfg {String} cls class of the element
649 * @cfg {Boolean} preventDefault (true|false) default false
650 * @cfg {Boolean} clickable (true|false) default false
653 * Create a new Element
654 * @param {Object} config The config object
657 Roo.bootstrap.Element = function(config){
658 Roo.bootstrap.Element.superclass.constructor.call(this, config);
664 * When a element is chick
665 * @param {Roo.bootstrap.Element} this
666 * @param {Roo.EventObject} e
672 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
677 preventDefault: false,
680 getAutoCreate : function(){
684 // cls: this.cls, double assign in parent class Component.js :: onRender
691 initEvents: function()
693 Roo.bootstrap.Element.superclass.initEvents.call(this);
696 this.el.on('click', this.onClick, this);
701 onClick : function(e)
703 if(this.preventDefault){
707 this.fireEvent('click', this, e);
710 getValue : function()
712 return this.el.dom.innerHTML;
715 setValue : function(value)
717 this.el.dom.innerHTML = value;
732 * @class Roo.bootstrap.DropTarget
733 * @extends Roo.bootstrap.Element
734 * Bootstrap DropTarget class
736 * @cfg {string} name dropable name
739 * Create a new Dropable Area
740 * @param {Object} config The config object
743 Roo.bootstrap.DropTarget = function(config){
744 Roo.bootstrap.DropTarget.superclass.constructor.call(this, config);
750 * When a element is chick
751 * @param {Roo.bootstrap.Element} this
752 * @param {Roo.EventObject} e
758 Roo.extend(Roo.bootstrap.DropTarget, Roo.bootstrap.Element, {
761 getAutoCreate : function(){
766 initEvents: function()
768 Roo.bootstrap.DropTarget.superclass.initEvents.call(this);
769 this.dropZone = new Roo.dd.DropTarget(this.getEl(), {
772 drop : this.dragDrop.createDelegate(this),
773 enter : this.dragEnter.createDelegate(this),
774 out : this.dragOut.createDelegate(this),
775 over : this.dragOver.createDelegate(this)
779 this.dropZone.DDM.useCache = false // so data gets refreshed when we resize stuff
782 dragDrop : function(source,e,data)
784 // user has to decide how to impliment this.
787 //this.fireEvent('drop', this, source, e ,data);
791 dragEnter : function(n, dd, e, data)
793 // probably want to resize the element to match the dropped element..
795 this.originalSize = this.el.getSize();
796 this.el.setSize( n.el.getSize());
797 this.dropZone.DDM.refreshCache(this.name);
798 Roo.log([n, dd, e, data]);
801 dragOut : function(value)
803 // resize back to normal
805 this.el.setSize(this.originalSize);
806 this.dropZone.resetConstraints();
809 dragOver : function()
826 * @class Roo.bootstrap.Body
827 * @extends Roo.bootstrap.Component
828 * Bootstrap Body class
832 * @param {Object} config The config object
835 Roo.bootstrap.Body = function(config){
837 config = config || {};
839 Roo.bootstrap.Body.superclass.constructor.call(this, config);
840 this.el = Roo.get(config.el ? config.el : document.body );
841 if (this.cls && this.cls.length) {
842 Roo.get(document.body).addClass(this.cls);
846 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
848 is_body : true,// just to make sure it's constructed?
853 onRender : function(ct, position)
855 /* Roo.log("Roo.bootstrap.Body - onRender");
856 if (this.cls && this.cls.length) {
857 Roo.get(document.body).addClass(this.cls);
876 * @class Roo.bootstrap.ButtonGroup
877 * @extends Roo.bootstrap.Component
878 * Bootstrap ButtonGroup class
879 * @cfg {String} size lg | sm | xs (default empty normal)
880 * @cfg {String} align vertical | justified (default none)
881 * @cfg {String} direction up | down (default down)
882 * @cfg {Boolean} toolbar false | true
883 * @cfg {Boolean} btn true | false
888 * @param {Object} config The config object
891 Roo.bootstrap.ButtonGroup = function(config){
892 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
895 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
903 getAutoCreate : function(){
909 cfg.html = this.html || cfg.html;
920 if (['vertical','justified'].indexOf(this.align)!==-1) {
921 cfg.cls = 'btn-group-' + this.align;
923 if (this.align == 'justified') {
924 console.log(this.items);
928 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
929 cfg.cls += ' btn-group-' + this.size;
932 if (this.direction == 'up') {
933 cfg.cls += ' dropup' ;
939 * Add a button to the group (similar to NavItem API.)
941 addItem : function(cfg)
943 var cn = new Roo.bootstrap.Button(cfg);
945 cn.parentId = this.id;
946 cn.onRender(this.el, null);
960 * @class Roo.bootstrap.Button
961 * @extends Roo.bootstrap.Component
962 * Bootstrap Button class
963 * @cfg {String} html The button content
964 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
965 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
966 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
967 * @cfg {String} size ( lg | sm | xs)
968 * @cfg {String} tag ( a | input | submit)
969 * @cfg {String} href empty or href
970 * @cfg {Boolean} disabled default false;
971 * @cfg {Boolean} isClose default false;
972 * @cfg {String} glyphicon depricated - use fa
973 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
974 * @cfg {String} badge text for badge
975 * @cfg {String} theme (default|glow)
976 * @cfg {Boolean} inverse dark themed version
977 * @cfg {Boolean} toggle is it a slidy toggle button
978 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
979 * @cfg {String} ontext text for on slidy toggle state
980 * @cfg {String} offtext text for off slidy toggle state
981 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
982 * @cfg {Boolean} removeClass remove the standard class..
983 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
986 * Create a new button
987 * @param {Object} config The config object
991 Roo.bootstrap.Button = function(config){
992 Roo.bootstrap.Button.superclass.constructor.call(this, config);
993 this.weightClass = ["btn-default btn-outline-secondary",
1005 * When a butotn is pressed
1006 * @param {Roo.bootstrap.Button} btn
1007 * @param {Roo.EventObject} e
1012 * After the button has been toggles
1013 * @param {Roo.bootstrap.Button} btn
1014 * @param {Roo.EventObject} e
1015 * @param {boolean} pressed (also available as button.pressed)
1021 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
1042 preventDefault: true,
1050 getAutoCreate : function(){
1058 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
1059 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
1060 this.tag = 'button';
1064 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
1066 if (this.toggle == true) {
1069 cls: 'slider-frame roo-button',
1073 'data-on-text':'ON',
1074 'data-off-text':'OFF',
1075 cls: 'slider-button',
1081 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
1082 cfg.cls += ' '+this.weight;
1089 cfg.cls += ' close';
1091 cfg["aria-hidden"] = true;
1093 cfg.html = "×";
1099 if (this.theme==='default') {
1100 cfg.cls = 'btn roo-button';
1102 //if (this.parentType != 'Navbar') {
1103 this.weight = this.weight.length ? this.weight : 'default';
1105 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
1107 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
1108 var weight = this.weight == 'default' ? 'secondary' : this.weight;
1109 cfg.cls += ' btn-' + outline + weight;
1110 if (this.weight == 'default') {
1112 cfg.cls += ' btn-' + this.weight;
1115 } else if (this.theme==='glow') {
1118 cfg.cls = 'btn-glow roo-button';
1120 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
1122 cfg.cls += ' ' + this.weight;
1128 this.cls += ' inverse';
1132 if (this.active || this.pressed === true) {
1133 cfg.cls += ' active';
1136 if (this.disabled) {
1137 cfg.disabled = 'disabled';
1141 Roo.log('changing to ul' );
1143 this.glyphicon = 'caret';
1144 if (Roo.bootstrap.version == 4) {
1145 this.fa = 'caret-down';
1150 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
1152 //gsRoo.log(this.parentType);
1153 if (this.parentType === 'Navbar' && !this.parent().bar) {
1154 Roo.log('changing to li?');
1163 href : this.href || '#'
1166 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
1167 cfg.cls += ' dropdown';
1174 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
1176 if (this.glyphicon) {
1177 cfg.html = ' ' + cfg.html;
1182 cls: 'glyphicon glyphicon-' + this.glyphicon
1187 cfg.html = ' ' + cfg.html;
1192 cls: 'fa fas fa-' + this.fa
1202 // cfg.cls='btn roo-button';
1206 var value = cfg.html;
1211 cls: 'glyphicon glyphicon-' + this.glyphicon,
1218 cls: 'fa fas fa-' + this.fa,
1223 var bw = this.badge_weight.length ? this.badge_weight :
1224 (this.weight.length ? this.weight : 'secondary');
1225 bw = bw == 'default' ? 'secondary' : bw;
1231 cls: 'badge badge-' + bw,
1240 cfg.cls += ' dropdown';
1241 cfg.html = typeof(cfg.html) != 'undefined' ?
1242 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
1245 if (cfg.tag !== 'a' && this.href !== '') {
1246 throw "Tag must be a to set href.";
1247 } else if (this.href.length > 0) {
1248 cfg.href = this.href;
1251 if(this.removeClass){
1256 cfg.target = this.target;
1261 initEvents: function() {
1262 // Roo.log('init events?');
1263 // Roo.log(this.el.dom);
1266 if (typeof (this.menu) != 'undefined') {
1267 this.menu.parentType = this.xtype;
1268 this.menu.triggerEl = this.el;
1269 this.addxtype(Roo.apply({}, this.menu));
1273 if (this.el.hasClass('roo-button')) {
1274 this.el.on('click', this.onClick, this);
1276 this.el.select('.roo-button').on('click', this.onClick, this);
1279 if(this.removeClass){
1280 this.el.on('click', this.onClick, this);
1283 this.el.enableDisplayMode();
1286 onClick : function(e)
1288 if (this.disabled) {
1292 Roo.log('button on click ');
1293 if(this.preventDefault){
1297 if (this.pressed === true || this.pressed === false) {
1298 this.toggleActive(e);
1302 this.fireEvent('click', this, e);
1306 * Enables this button
1310 this.disabled = false;
1311 this.el.removeClass('disabled');
1315 * Disable this button
1317 disable : function()
1319 this.disabled = true;
1320 this.el.addClass('disabled');
1323 * sets the active state on/off,
1324 * @param {Boolean} state (optional) Force a particular state
1326 setActive : function(v) {
1328 this.el[v ? 'addClass' : 'removeClass']('active');
1332 * toggles the current active state
1334 toggleActive : function(e)
1336 this.setActive(!this.pressed);
1337 this.fireEvent('toggle', this, e, !this.pressed);
1340 * get the current active state
1341 * @return {boolean} true if it's active
1343 isActive : function()
1345 return this.el.hasClass('active');
1348 * set the text of the first selected button
1350 setText : function(str)
1352 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
1355 * get the text of the first selected button
1357 getText : function()
1359 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
1362 setWeight : function(str)
1364 this.el.removeClass(this.weightClass);
1366 var outline = this.outline ? 'outline-' : '';
1367 if (str == 'default') {
1368 this.el.addClass('btn-default btn-outline-secondary');
1371 this.el.addClass('btn-' + outline + str);
1385 * @class Roo.bootstrap.Column
1386 * @extends Roo.bootstrap.Component
1387 * Bootstrap Column class
1388 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1389 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1390 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1391 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1392 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1393 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1394 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1395 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1398 * @cfg {Boolean} hidden (true|false) hide the element
1399 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1400 * @cfg {String} fa (ban|check|...) font awesome icon
1401 * @cfg {Number} fasize (1|2|....) font awsome size
1403 * @cfg {String} icon (info-sign|check|...) glyphicon name
1405 * @cfg {String} html content of column.
1408 * Create a new Column
1409 * @param {Object} config The config object
1412 Roo.bootstrap.Column = function(config){
1413 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1416 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1434 getAutoCreate : function(){
1435 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1443 var sizes = ['xs','sm','md','lg'];
1444 sizes.map(function(size ,ix){
1445 //Roo.log( size + ':' + settings[size]);
1447 if (settings[size+'off'] !== false) {
1448 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1451 if (settings[size] === false) {
1455 if (!settings[size]) { // 0 = hidden
1456 cfg.cls += ' hidden-' + size + ' hidden-' + size + '-down';
1458 for (var i = ix; i > -1; i--) {
1459 cfg.cls += ' d-' + sizes[i] + '-none';
1465 cfg.cls += ' col-' + size + '-' + settings[size] + (
1466 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1472 cfg.cls += ' hidden';
1475 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1476 cfg.cls +=' alert alert-' + this.alert;
1480 if (this.html.length) {
1481 cfg.html = this.html;
1485 if (this.fasize > 1) {
1486 fasize = ' fa-' + this.fasize + 'x';
1488 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1493 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1512 * @class Roo.bootstrap.Container
1513 * @extends Roo.bootstrap.Component
1514 * Bootstrap Container class
1515 * @cfg {Boolean} jumbotron is it a jumbotron element
1516 * @cfg {String} html content of element
1517 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1518 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1519 * @cfg {String} header content of header (for panel)
1520 * @cfg {String} footer content of footer (for panel)
1521 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1522 * @cfg {String} tag (header|aside|section) type of HTML tag.
1523 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1524 * @cfg {String} fa font awesome icon
1525 * @cfg {String} icon (info-sign|check|...) glyphicon name
1526 * @cfg {Boolean} hidden (true|false) hide the element
1527 * @cfg {Boolean} expandable (true|false) default false
1528 * @cfg {Boolean} expanded (true|false) default true
1529 * @cfg {String} rheader contet on the right of header
1530 * @cfg {Boolean} clickable (true|false) default false
1534 * Create a new Container
1535 * @param {Object} config The config object
1538 Roo.bootstrap.Container = function(config){
1539 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1545 * After the panel has been expand
1547 * @param {Roo.bootstrap.Container} this
1552 * After the panel has been collapsed
1554 * @param {Roo.bootstrap.Container} this
1559 * When a element is chick
1560 * @param {Roo.bootstrap.Container} this
1561 * @param {Roo.EventObject} e
1567 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1585 getChildContainer : function() {
1591 if (this.panel.length) {
1592 return this.el.select('.panel-body',true).first();
1599 getAutoCreate : function(){
1602 tag : this.tag || 'div',
1606 if (this.jumbotron) {
1607 cfg.cls = 'jumbotron';
1612 // - this is applied by the parent..
1614 // cfg.cls = this.cls + '';
1617 if (this.sticky.length) {
1619 var bd = Roo.get(document.body);
1620 if (!bd.hasClass('bootstrap-sticky')) {
1621 bd.addClass('bootstrap-sticky');
1622 Roo.select('html',true).setStyle('height', '100%');
1625 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1629 if (this.well.length) {
1630 switch (this.well) {
1633 cfg.cls +=' well well-' +this.well;
1642 cfg.cls += ' hidden';
1646 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1647 cfg.cls +=' alert alert-' + this.alert;
1652 if (this.panel.length) {
1653 cfg.cls += ' panel panel-' + this.panel;
1655 if (this.header.length) {
1659 if(this.expandable){
1661 cfg.cls = cfg.cls + ' expandable';
1665 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1673 cls : 'panel-title',
1674 html : (this.expandable ? ' ' : '') + this.header
1678 cls: 'panel-header-right',
1684 cls : 'panel-heading',
1685 style : this.expandable ? 'cursor: pointer' : '',
1693 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1698 if (this.footer.length) {
1700 cls : 'panel-footer',
1709 body.html = this.html || cfg.html;
1710 // prefix with the icons..
1712 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1715 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1720 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1721 cfg.cls = 'container';
1727 initEvents: function()
1729 if(this.expandable){
1730 var headerEl = this.headerEl();
1733 headerEl.on('click', this.onToggleClick, this);
1738 this.el.on('click', this.onClick, this);
1743 onToggleClick : function()
1745 var headerEl = this.headerEl();
1761 if(this.fireEvent('expand', this)) {
1763 this.expanded = true;
1765 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1767 this.el.select('.panel-body',true).first().removeClass('hide');
1769 var toggleEl = this.toggleEl();
1775 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1780 collapse : function()
1782 if(this.fireEvent('collapse', this)) {
1784 this.expanded = false;
1786 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1787 this.el.select('.panel-body',true).first().addClass('hide');
1789 var toggleEl = this.toggleEl();
1795 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1799 toggleEl : function()
1801 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1805 return this.el.select('.panel-heading .fa',true).first();
1808 headerEl : function()
1810 if(!this.el || !this.panel.length || !this.header.length){
1814 return this.el.select('.panel-heading',true).first()
1819 if(!this.el || !this.panel.length){
1823 return this.el.select('.panel-body',true).first()
1826 titleEl : function()
1828 if(!this.el || !this.panel.length || !this.header.length){
1832 return this.el.select('.panel-title',true).first();
1835 setTitle : function(v)
1837 var titleEl = this.titleEl();
1843 titleEl.dom.innerHTML = v;
1846 getTitle : function()
1849 var titleEl = this.titleEl();
1855 return titleEl.dom.innerHTML;
1858 setRightTitle : function(v)
1860 var t = this.el.select('.panel-header-right',true).first();
1866 t.dom.innerHTML = v;
1869 onClick : function(e)
1873 this.fireEvent('click', this, e);
1880 * This is BS4's Card element.. - similar to our containers probably..
1884 * @class Roo.bootstrap.Card
1885 * @extends Roo.bootstrap.Component
1886 * Bootstrap Card class
1889 * possible... may not be implemented..
1890 * @cfg {String} header_image src url of image.
1891 * @cfg {String|Object} header
1892 * @cfg {Number} header_size (0|1|2|3|4|5) H1 or H2 etc.. 0 indicates default
1894 * @cfg {String} title
1895 * @cfg {String} subtitle
1896 * @cfg {String} html -- html contents - or just use children..
1897 * @cfg {String} footer
1899 * @cfg {String} weight (primary|warning|info|danger|secondary|success|light|dark)
1901 * @cfg {String} margin (0|1|2|3|4|5|auto)
1902 * @cfg {String} margin_top (0|1|2|3|4|5|auto)
1903 * @cfg {String} margin_bottom (0|1|2|3|4|5|auto)
1904 * @cfg {String} margin_left (0|1|2|3|4|5|auto)
1905 * @cfg {String} margin_right (0|1|2|3|4|5|auto)
1906 * @cfg {String} margin_x (0|1|2|3|4|5|auto)
1907 * @cfg {String} margin_y (0|1|2|3|4|5|auto)
1909 * @cfg {String} padding (0|1|2|3|4|5)
1910 * @cfg {String} padding_top (0|1|2|3|4|5)
1911 * @cfg {String} padding_bottom (0|1|2|3|4|5)
1912 * @cfg {String} padding_left (0|1|2|3|4|5)
1913 * @cfg {String} padding_right (0|1|2|3|4|5)
1914 * @cfg {String} padding_x (0|1|2|3|4|5)
1915 * @cfg {String} padding_y (0|1|2|3|4|5)
1917 * @cfg {String} display (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1918 * @cfg {String} display_xs (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1919 * @cfg {String} display_sm (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1920 * @cfg {String} display_lg (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1921 * @cfg {String} display_xl (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1923 * @config {Boolean} dragable if this card can be dragged.
1924 * @config {String} drag_group group for drag
1925 * @config {Boolean} dropable if this card can recieve other cards being dropped onto it..
1926 * @config {String} drop_group group for drag
1928 * @config {Boolean} collapsable can the body be collapsed.
1929 * @config {Boolean} collapsed is the body collapsed when rendered...
1931 * Create a new Container
1932 * @param {Object} config The config object
1935 Roo.bootstrap.Card = function(config){
1936 Roo.bootstrap.Card.superclass.constructor.call(this, config);
1942 * When a element a card is dropped
1943 * @param {Roo.bootstrap.Element} this
1944 * @param {Roo.Element} n the node being dropped?
1945 * @param {Object} dd Drag and drop data
1946 * @param {Roo.EventObject} e
1947 * @param {Roo.EventObject} data the data passed via getDragData
1955 Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component, {
1960 margin: '', /// may be better in component?
1990 collapsable : false,
1997 childContainer : false,
1998 dropEl : false, /// the dom placeholde element that indicates drop location.
2000 layoutCls : function()
2004 Roo.log(this.margin_bottom.length);
2005 ['', 'top', 'bottom', 'left', 'right', 'x', 'y' ].forEach(function(v) {
2006 // in theory these can do margin_top : ml-xs-3 ??? but we don't support that yet
2008 if (('' + t['margin' + (v.length ? '_' : '') + v]).length) {
2009 cls += ' m' + (v.length ? v[0] : '') + '-' + t['margin' + (v.length ? '_' : '') + v];
2011 if (('' + t['padding' + (v.length ? '_' : '') + v]).length) {
2012 cls += ' p' + (v.length ? v[0] : '') + '-' + t['padding' + (v.length ? '_' : '') + v];
2016 ['', 'xs', 'sm', 'lg', 'xl'].forEach(function(v) {
2017 if (('' + t['display' + (v.length ? '_' : '') + v]).length) {
2018 cls += ' d' + (v.length ? '-' : '') + v + '-' + t['margin' + (v.length ? '_' : '') + v]
2022 // more generic support?
2030 // Roo.log("Call onRender: " + this.xtype);
2031 /* We are looking at something like this.
2033 <img src="..." class="card-img-top" alt="...">
2034 <div class="card-body">
2035 <h5 class="card-title">Card title</h5>
2036 <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
2038 >> this bit is really the body...
2039 <div> << we will ad dthis in hopefully it will not break shit.
2041 ** card text does not actually have any styling...
2043 <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
2046 <a href="#" class="card-link">Card link</a>
2049 <div class="card-footer">
2050 <small class="text-muted">Last updated 3 mins ago</small>
2054 getAutoCreate : function(){
2062 if (this.weight.length && this.weight != 'light') {
2063 cfg.cls += ' text-white';
2065 cfg.cls += ' text-dark'; // need as it's nested..
2067 if (this.weight.length) {
2068 cfg.cls += ' bg-' + this.weight;
2071 cfg.cls += this.layoutCls();
2074 if (this.header.length) {
2076 tag : this.header_size > 0 ? 'h' + this.header_size : 'div',
2077 cls : 'card-header',
2085 cls : 'card-header d-none',
2090 if (this.collapsable) {
2093 cls : 'd-block user-select-none',
2097 cls : 'roo-collapse-toggle fa fa-chevron-down float-right'
2102 hdr.cn.push(hdr_ctr);
2104 if (this.header.length) {
2107 cls: 'roo-card-header-ctr',
2112 if (this.header_image.length) {
2115 cls : 'card-img-top',
2116 src: this.header_image // escape?
2121 cls : 'card-img-top d-none'
2131 if (this.collapsable) {
2134 cls : 'roo-collapsable collapse ' + (this.collapsed ? '' : 'show'),
2141 if (this.title.length) {
2145 src: this.title // escape?
2149 if (this.subtitle.length) {
2153 src: this.subtitle // escape?
2159 cls : 'roo-card-body-ctr'
2162 if (this.html.length) {
2168 // fixme ? handle objects?
2169 if (this.footer.length) {
2172 cls : 'card-footer',
2173 html: this.footer // escape?
2182 getCardHeader : function()
2184 var ret = this.el.select('.card-header',true).first();
2185 if (ret.hasClass('d-none')) {
2186 ret.removeClass('d-none');
2192 getCardImageTop : function()
2194 var ret = this.el.select('.card-img-top',true).first();
2195 if (ret.hasClass('d-none')) {
2196 ret.removeClass('d-none');
2202 getChildContainer : function()
2208 return this.el.select('.roo-card-body-ctr',true).first();
2211 initEvents: function()
2214 this.bodyEl = this.getChildContainer();
2216 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
2217 containerScroll: true,
2218 ddGroup: this.drag_group || 'default_card_drag_group'
2220 this.dragZone.getDragData = this.getDragData.createDelegate(this);
2222 if (this.dropable) {
2223 this.dropZone = new Roo.dd.DropZone(this.el.select('.card-body',true).first() , {
2224 containerScroll: true,
2225 ddGroup: this.drop_group || 'default_card_drag_group'
2227 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
2228 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
2229 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
2230 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
2231 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
2234 if (this.collapsable) {
2235 this.el.select('.card-header',true).on('click', this.onToggleCollapse, this);
2238 getDragData : function(e)
2240 var target = this.getEl();
2242 //this.handleSelection(e);
2247 nodes: this.getEl(),
2252 dragData.ddel = target.dom ; // the div element
2253 Roo.log(target.getWidth( ));
2254 dragData.ddel.style.width = target.getWidth() + 'px';
2261 * Part of the Roo.dd.DropZone interface. If no target node is found, the
2262 * whole Element becomes the target, and this causes the drop gesture to append.
2264 getTargetFromEvent : function(e, dragged_card_el)
2266 var target = e.getTarget();
2267 while ((target !== null) && (target.parentNode != this.bodyEl.dom)) {
2268 target = target.parentNode;
2270 //Roo.log([ 'target' , target ? target.id : '--nothing--']);
2271 // see if target is one of the 'cards'...
2274 //Roo.log(this.items.length);
2275 var lpos = pos = cpos = false;
2276 for (var i = 0;i< this.items.length;i++) {
2278 if (!this.items[i].el.hasClass('card')) {
2281 pos = this.getDropPoint(e, this.items[i].el.dom);
2283 //Roo.log(this.items[i].el.dom.id);
2284 var ii = cards.length;
2285 cards.push(this.items[i]);
2287 if (ctarget < 0 && pos == 'above') {
2288 ctarget = ii > 0 ? ii - 1 : 0;
2289 cpos = ii > 0 ? 'below' : pos;
2292 if (!cards.length) {
2293 return [ true, 'below' ];
2297 ctarget = cards.length -1;
2300 if (cards[ctarget].el == dragged_card_el) {
2304 if (cpos == 'below') {
2305 var card_after = ctarget+1 == cards.length ? false : cards[ctarget+1];
2307 // then above should not be dragged_card_el.
2310 if (card_after && card_after.el == dragged_card_el) {
2313 return [ cards[ctarget], cpos ];
2317 var card_before = ctarget > 0 ? cards[ctarget-1] : false;
2320 if (card_before && card_before.el == dragged_card_el) {
2324 return [ cards[ctarget], cpos, cards, ctarget ];
2327 onNodeEnter : function(n, dd, e, data){
2330 onNodeOver : function(n, dd, e, data)
2333 var target_info = this.getTargetFromEvent(e,data.source.el);
2334 if (target_info === false) {
2335 this.dropPlaceHolder('hide');
2338 Roo.log(['getTargetFromEvent', target_info[0].el.dom.id,target_info[1]]);
2341 this.dropPlaceHolder('show', target_info,data);
2345 onNodeOut : function(n, dd, e, data){
2346 this.dropPlaceHolder('hide');
2349 onNodeDrop : function(n, dd, e, data)
2352 // call drop - return false if
2353 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
2357 var target_info = this.getTargetFromEvent(e,data.source.el);
2358 if (target_info === false) {
2362 var pt = this.getDropPoint(e, n, dd);
2363 var insertAt = (n == this.bodyEl.dom) ? this.items.length : n.nodeIndex;
2364 if (pt == "below") {
2367 for (var i = 0; i < this.items.length; i++) {
2368 var r = this.items[i];
2369 //var dup = this.store.getById(r.id);
2370 if (dup && (dd != this.dragZone)) {
2371 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
2374 this.store.insert(insertAt++, r.copy());
2376 data.source.isDirtyFlag = true;
2378 this.store.insert(insertAt++, r);
2380 this.isDirtyFlag = true;
2383 this.dragZone.cachedTarget = null;
2387 /** Decide whether to drop above or below a View node. */
2388 getDropPoint : function(e, n, dd)
2393 if (n == this.bodyEl.dom) {
2396 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
2397 var c = t + (b - t) / 2;
2398 var y = Roo.lib.Event.getPageY(e);
2405 onToggleCollapse : function(e)
2407 if (this.collapsed) {
2408 this.el.select('.roo-collapse-toggle').removeClass('collapsed');
2409 this.el.select('.roo-collapsable').addClass('show');
2410 this.collapsed = false;
2413 this.el.select('.roo-collapse-toggle').addClass('collapsed');
2414 this.el.select('.roo-collapsable').removeClass('show');
2415 this.collapsed = true;
2419 dropPlaceHolder: function (action, where_ar, data)
2421 if (this.dropEl === false) {
2422 this.dropEl = Roo.DomHelper.append(this.bodyEl, {
2426 this.dropEl.removeClass(['d-none', 'd-block']);
2427 if (action == 'hide') {
2429 this.dropEl.addClass('d-none');
2432 var cardel = where_ar[0].el.dom;
2434 this.dropEl.dom.parentNode.removeChild(this.dropEl.dom);
2435 if (where_ar[1] == 'above') {
2436 cardel.parentNode.insertBefore(this.dropEl.dom, cardel);
2437 } else if (cardel.nextSibling) {
2438 cardel.parentNode.insertBefore(this.dropEl.dom,cardel.nextSibling);
2440 cardel.parentNode.append(this.dropEl.dom);
2442 this.dropEl.addClass('d-block roo-card-dropzone');
2444 this.dropEl.setHeight( Roo.get(data.ddel).getHeight() );
2458 * Card header - holder for the card header elements.
2463 * @class Roo.bootstrap.CardHeader
2464 * @extends Roo.bootstrap.Element
2465 * Bootstrap CardHeader class
2467 * Create a new Card Header - that you can embed children into
2468 * @param {Object} config The config object
2471 Roo.bootstrap.CardHeader = function(config){
2472 Roo.bootstrap.CardHeader.superclass.constructor.call(this, config);
2475 Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element, {
2478 container_method : 'getCardHeader'
2491 * Card header - holder for the card header elements.
2496 * @class Roo.bootstrap.CardImageTop
2497 * @extends Roo.bootstrap.Element
2498 * Bootstrap CardImageTop class
2500 * Create a new Card Image Top container
2501 * @param {Object} config The config object
2504 Roo.bootstrap.CardImageTop = function(config){
2505 Roo.bootstrap.CardImageTop.superclass.constructor.call(this, config);
2508 Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element, {
2511 container_method : 'getCardImageTop'
2529 * @class Roo.bootstrap.Img
2530 * @extends Roo.bootstrap.Component
2531 * Bootstrap Img class
2532 * @cfg {Boolean} imgResponsive false | true
2533 * @cfg {String} border rounded | circle | thumbnail
2534 * @cfg {String} src image source
2535 * @cfg {String} alt image alternative text
2536 * @cfg {String} href a tag href
2537 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
2538 * @cfg {String} xsUrl xs image source
2539 * @cfg {String} smUrl sm image source
2540 * @cfg {String} mdUrl md image source
2541 * @cfg {String} lgUrl lg image source
2544 * Create a new Input
2545 * @param {Object} config The config object
2548 Roo.bootstrap.Img = function(config){
2549 Roo.bootstrap.Img.superclass.constructor.call(this, config);
2555 * The img click event for the img.
2556 * @param {Roo.EventObject} e
2562 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
2564 imgResponsive: true,
2574 getAutoCreate : function()
2576 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2577 return this.createSingleImg();
2582 cls: 'roo-image-responsive-group',
2587 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
2589 if(!_this[size + 'Url']){
2595 cls: (_this.imgResponsive) ? 'img-responsive' : '',
2596 html: _this.html || cfg.html,
2597 src: _this[size + 'Url']
2600 img.cls += ' roo-image-responsive-' + size;
2602 var s = ['xs', 'sm', 'md', 'lg'];
2604 s.splice(s.indexOf(size), 1);
2606 Roo.each(s, function(ss){
2607 img.cls += ' hidden-' + ss;
2610 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
2611 cfg.cls += ' img-' + _this.border;
2615 cfg.alt = _this.alt;
2628 a.target = _this.target;
2632 cfg.cn.push((_this.href) ? a : img);
2639 createSingleImg : function()
2643 cls: (this.imgResponsive) ? 'img-responsive' : '',
2645 src : 'about:blank' // just incase src get's set to undefined?!?
2648 cfg.html = this.html || cfg.html;
2650 cfg.src = this.src || cfg.src;
2652 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
2653 cfg.cls += ' img-' + this.border;
2670 a.target = this.target;
2675 return (this.href) ? a : cfg;
2678 initEvents: function()
2681 this.el.on('click', this.onClick, this);
2686 onClick : function(e)
2688 Roo.log('img onclick');
2689 this.fireEvent('click', this, e);
2692 * Sets the url of the image - used to update it
2693 * @param {String} url the url of the image
2696 setSrc : function(url)
2700 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2701 this.el.dom.src = url;
2705 this.el.select('img', true).first().dom.src = url;
2721 * @class Roo.bootstrap.Link
2722 * @extends Roo.bootstrap.Component
2723 * Bootstrap Link Class
2724 * @cfg {String} alt image alternative text
2725 * @cfg {String} href a tag href
2726 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
2727 * @cfg {String} html the content of the link.
2728 * @cfg {String} anchor name for the anchor link
2729 * @cfg {String} fa - favicon
2731 * @cfg {Boolean} preventDefault (true | false) default false
2735 * Create a new Input
2736 * @param {Object} config The config object
2739 Roo.bootstrap.Link = function(config){
2740 Roo.bootstrap.Link.superclass.constructor.call(this, config);
2746 * The img click event for the img.
2747 * @param {Roo.EventObject} e
2753 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
2757 preventDefault: false,
2763 getAutoCreate : function()
2765 var html = this.html || '';
2767 if (this.fa !== false) {
2768 html = '<i class="fa fa-' + this.fa + '"></i>';
2773 // anchor's do not require html/href...
2774 if (this.anchor === false) {
2776 cfg.href = this.href || '#';
2778 cfg.name = this.anchor;
2779 if (this.html !== false || this.fa !== false) {
2782 if (this.href !== false) {
2783 cfg.href = this.href;
2787 if(this.alt !== false){
2792 if(this.target !== false) {
2793 cfg.target = this.target;
2799 initEvents: function() {
2801 if(!this.href || this.preventDefault){
2802 this.el.on('click', this.onClick, this);
2806 onClick : function(e)
2808 if(this.preventDefault){
2811 //Roo.log('img onclick');
2812 this.fireEvent('click', this, e);
2825 * @class Roo.bootstrap.Header
2826 * @extends Roo.bootstrap.Component
2827 * Bootstrap Header class
2828 * @cfg {String} html content of header
2829 * @cfg {Number} level (1|2|3|4|5|6) default 1
2832 * Create a new Header
2833 * @param {Object} config The config object
2837 Roo.bootstrap.Header = function(config){
2838 Roo.bootstrap.Header.superclass.constructor.call(this, config);
2841 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
2849 getAutoCreate : function(){
2854 tag: 'h' + (1 *this.level),
2855 html: this.html || ''
2867 * Ext JS Library 1.1.1
2868 * Copyright(c) 2006-2007, Ext JS, LLC.
2870 * Originally Released Under LGPL - original licence link has changed is not relivant.
2873 * <script type="text/javascript">
2877 * @class Roo.bootstrap.MenuMgr
2878 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
2881 Roo.bootstrap.MenuMgr = function(){
2882 var menus, active, groups = {}, attached = false, lastShow = new Date();
2884 // private - called when first menu is created
2887 active = new Roo.util.MixedCollection();
2888 Roo.get(document).addKeyListener(27, function(){
2889 if(active.length > 0){
2897 if(active && active.length > 0){
2898 var c = active.clone();
2908 if(active.length < 1){
2909 Roo.get(document).un("mouseup", onMouseDown);
2917 var last = active.last();
2918 lastShow = new Date();
2921 Roo.get(document).on("mouseup", onMouseDown);
2926 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
2927 m.parentMenu.activeChild = m;
2928 }else if(last && last.isVisible()){
2929 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
2934 function onBeforeHide(m){
2936 m.activeChild.hide();
2938 if(m.autoHideTimer){
2939 clearTimeout(m.autoHideTimer);
2940 delete m.autoHideTimer;
2945 function onBeforeShow(m){
2946 var pm = m.parentMenu;
2947 if(!pm && !m.allowOtherMenus){
2949 }else if(pm && pm.activeChild && active != m){
2950 pm.activeChild.hide();
2954 // private this should really trigger on mouseup..
2955 function onMouseDown(e){
2956 Roo.log("on Mouse Up");
2958 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
2959 Roo.log("MenuManager hideAll");
2968 function onBeforeCheck(mi, state){
2970 var g = groups[mi.group];
2971 for(var i = 0, l = g.length; i < l; i++){
2973 g[i].setChecked(false);
2982 * Hides all menus that are currently visible
2984 hideAll : function(){
2989 register : function(menu){
2993 menus[menu.id] = menu;
2994 menu.on("beforehide", onBeforeHide);
2995 menu.on("hide", onHide);
2996 menu.on("beforeshow", onBeforeShow);
2997 menu.on("show", onShow);
2999 if(g && menu.events["checkchange"]){
3003 groups[g].push(menu);
3004 menu.on("checkchange", onCheck);
3009 * Returns a {@link Roo.menu.Menu} object
3010 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
3011 * be used to generate and return a new Menu instance.
3013 get : function(menu){
3014 if(typeof menu == "string"){ // menu id
3016 }else if(menu.events){ // menu instance
3019 /*else if(typeof menu.length == 'number'){ // array of menu items?
3020 return new Roo.bootstrap.Menu({items:menu});
3021 }else{ // otherwise, must be a config
3022 return new Roo.bootstrap.Menu(menu);
3029 unregister : function(menu){
3030 delete menus[menu.id];
3031 menu.un("beforehide", onBeforeHide);
3032 menu.un("hide", onHide);
3033 menu.un("beforeshow", onBeforeShow);
3034 menu.un("show", onShow);
3036 if(g && menu.events["checkchange"]){
3037 groups[g].remove(menu);
3038 menu.un("checkchange", onCheck);
3043 registerCheckable : function(menuItem){
3044 var g = menuItem.group;
3049 groups[g].push(menuItem);
3050 menuItem.on("beforecheckchange", onBeforeCheck);
3055 unregisterCheckable : function(menuItem){
3056 var g = menuItem.group;
3058 groups[g].remove(menuItem);
3059 menuItem.un("beforecheckchange", onBeforeCheck);
3071 * @class Roo.bootstrap.Menu
3072 * @extends Roo.bootstrap.Component
3073 * Bootstrap Menu class - container for MenuItems
3074 * @cfg {String} type (dropdown|treeview|submenu) type of menu
3075 * @cfg {bool} hidden if the menu should be hidden when rendered.
3076 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
3077 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
3081 * @param {Object} config The config object
3085 Roo.bootstrap.Menu = function(config){
3086 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
3087 if (this.registerMenu && this.type != 'treeview') {
3088 Roo.bootstrap.MenuMgr.register(this);
3095 * Fires before this menu is displayed (return false to block)
3096 * @param {Roo.menu.Menu} this
3101 * Fires before this menu is hidden (return false to block)
3102 * @param {Roo.menu.Menu} this
3107 * Fires after this menu is displayed
3108 * @param {Roo.menu.Menu} this
3113 * Fires after this menu is hidden
3114 * @param {Roo.menu.Menu} this
3119 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
3120 * @param {Roo.menu.Menu} this
3121 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3122 * @param {Roo.EventObject} e
3127 * Fires when the mouse is hovering over this menu
3128 * @param {Roo.menu.Menu} this
3129 * @param {Roo.EventObject} e
3130 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3135 * Fires when the mouse exits this menu
3136 * @param {Roo.menu.Menu} this
3137 * @param {Roo.EventObject} e
3138 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3143 * Fires when a menu item contained in this menu is clicked
3144 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
3145 * @param {Roo.EventObject} e
3149 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
3152 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
3156 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
3159 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
3161 registerMenu : true,
3163 menuItems :false, // stores the menu items..
3173 getChildContainer : function() {
3177 getAutoCreate : function(){
3179 //if (['right'].indexOf(this.align)!==-1) {
3180 // cfg.cn[1].cls += ' pull-right'
3186 cls : 'dropdown-menu' ,
3187 style : 'z-index:1000'
3191 if (this.type === 'submenu') {
3192 cfg.cls = 'submenu active';
3194 if (this.type === 'treeview') {
3195 cfg.cls = 'treeview-menu';
3200 initEvents : function() {
3202 // Roo.log("ADD event");
3203 // Roo.log(this.triggerEl.dom);
3205 this.triggerEl.on('click', this.onTriggerClick, this);
3207 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
3210 if (this.triggerEl.hasClass('nav-item')) {
3211 // dropdown toggle on the 'a' in BS4?
3212 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
3214 this.triggerEl.addClass('dropdown-toggle');
3217 this.el.on('touchstart' , this.onTouch, this);
3219 this.el.on('click' , this.onClick, this);
3221 this.el.on("mouseover", this.onMouseOver, this);
3222 this.el.on("mouseout", this.onMouseOut, this);
3226 findTargetItem : function(e)
3228 var t = e.getTarget(".dropdown-menu-item", this.el, true);
3232 //Roo.log(t); Roo.log(t.id);
3234 //Roo.log(this.menuitems);
3235 return this.menuitems.get(t.id);
3237 //return this.items.get(t.menuItemId);
3243 onTouch : function(e)
3245 Roo.log("menu.onTouch");
3246 //e.stopEvent(); this make the user popdown broken
3250 onClick : function(e)
3252 Roo.log("menu.onClick");
3254 var t = this.findTargetItem(e);
3255 if(!t || t.isContainer){
3260 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
3261 if(t == this.activeItem && t.shouldDeactivate(e)){
3262 this.activeItem.deactivate();
3263 delete this.activeItem;
3267 this.setActiveItem(t, true);
3275 Roo.log('pass click event');
3279 this.fireEvent("click", this, t, e);
3283 if(!t.href.length || t.href == '#'){
3284 (function() { _this.hide(); }).defer(100);
3289 onMouseOver : function(e){
3290 var t = this.findTargetItem(e);
3293 // if(t.canActivate && !t.disabled){
3294 // this.setActiveItem(t, true);
3298 this.fireEvent("mouseover", this, e, t);
3300 isVisible : function(){
3301 return !this.hidden;
3303 onMouseOut : function(e){
3304 var t = this.findTargetItem(e);
3307 // if(t == this.activeItem && t.shouldDeactivate(e)){
3308 // this.activeItem.deactivate();
3309 // delete this.activeItem;
3312 this.fireEvent("mouseout", this, e, t);
3317 * Displays this menu relative to another element
3318 * @param {String/HTMLElement/Roo.Element} element The element to align to
3319 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
3320 * the element (defaults to this.defaultAlign)
3321 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3323 show : function(el, pos, parentMenu)
3325 if (false === this.fireEvent("beforeshow", this)) {
3326 Roo.log("show canceled");
3329 this.parentMenu = parentMenu;
3334 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
3337 * Displays this menu at a specific xy position
3338 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
3339 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3341 showAt : function(xy, parentMenu, /* private: */_e){
3342 this.parentMenu = parentMenu;
3347 this.fireEvent("beforeshow", this);
3348 //xy = this.el.adjustForConstraints(xy);
3352 this.hideMenuItems();
3353 this.hidden = false;
3354 this.triggerEl.addClass('open');
3355 this.el.addClass('show');
3357 // reassign x when hitting right
3358 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
3359 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
3362 // reassign y when hitting bottom
3363 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
3364 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
3367 // but the list may align on trigger left or trigger top... should it be a properity?
3369 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
3374 this.fireEvent("show", this);
3380 this.doFocus.defer(50, this);
3384 doFocus : function(){
3386 this.focusEl.focus();
3391 * Hides this menu and optionally all parent menus
3392 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
3394 hide : function(deep)
3396 if (false === this.fireEvent("beforehide", this)) {
3397 Roo.log("hide canceled");
3400 this.hideMenuItems();
3401 if(this.el && this.isVisible()){
3403 if(this.activeItem){
3404 this.activeItem.deactivate();
3405 this.activeItem = null;
3407 this.triggerEl.removeClass('open');;
3408 this.el.removeClass('show');
3410 this.fireEvent("hide", this);
3412 if(deep === true && this.parentMenu){
3413 this.parentMenu.hide(true);
3417 onTriggerClick : function(e)
3419 Roo.log('trigger click');
3421 var target = e.getTarget();
3423 Roo.log(target.nodeName.toLowerCase());
3425 if(target.nodeName.toLowerCase() === 'i'){
3431 onTriggerPress : function(e)
3433 Roo.log('trigger press');
3434 //Roo.log(e.getTarget());
3435 // Roo.log(this.triggerEl.dom);
3437 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
3438 var pel = Roo.get(e.getTarget());
3439 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
3440 Roo.log('is treeview or dropdown?');
3444 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
3448 if (this.isVisible()) {
3453 this.show(this.triggerEl, '?', false);
3456 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
3463 hideMenuItems : function()
3465 Roo.log("hide Menu Items");
3470 this.el.select('.open',true).each(function(aa) {
3472 aa.removeClass('open');
3476 addxtypeChild : function (tree, cntr) {
3477 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
3479 this.menuitems.add(comp);
3491 this.getEl().dom.innerHTML = '';
3492 this.menuitems.clear();
3506 * @class Roo.bootstrap.MenuItem
3507 * @extends Roo.bootstrap.Component
3508 * Bootstrap MenuItem class
3509 * @cfg {String} html the menu label
3510 * @cfg {String} href the link
3511 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
3512 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
3513 * @cfg {Boolean} active used on sidebars to highlight active itesm
3514 * @cfg {String} fa favicon to show on left of menu item.
3515 * @cfg {Roo.bootsrap.Menu} menu the child menu.
3519 * Create a new MenuItem
3520 * @param {Object} config The config object
3524 Roo.bootstrap.MenuItem = function(config){
3525 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
3530 * The raw click event for the entire grid.
3531 * @param {Roo.bootstrap.MenuItem} this
3532 * @param {Roo.EventObject} e
3538 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
3542 preventDefault: false,
3543 isContainer : false,
3547 getAutoCreate : function(){
3549 if(this.isContainer){
3552 cls: 'dropdown-menu-item '
3562 cls : 'dropdown-item',
3567 if (this.fa !== false) {
3570 cls : 'fa fa-' + this.fa
3579 cls: 'dropdown-menu-item',
3582 if (this.parent().type == 'treeview') {
3583 cfg.cls = 'treeview-menu';
3586 cfg.cls += ' active';
3591 anc.href = this.href || cfg.cn[0].href ;
3592 ctag.html = this.html || cfg.cn[0].html ;
3596 initEvents: function()
3598 if (this.parent().type == 'treeview') {
3599 this.el.select('a').on('click', this.onClick, this);
3603 this.menu.parentType = this.xtype;
3604 this.menu.triggerEl = this.el;
3605 this.menu = this.addxtype(Roo.apply({}, this.menu));
3609 onClick : function(e)
3611 Roo.log('item on click ');
3613 if(this.preventDefault){
3616 //this.parent().hideMenuItems();
3618 this.fireEvent('click', this, e);
3637 * @class Roo.bootstrap.MenuSeparator
3638 * @extends Roo.bootstrap.Component
3639 * Bootstrap MenuSeparator class
3642 * Create a new MenuItem
3643 * @param {Object} config The config object
3647 Roo.bootstrap.MenuSeparator = function(config){
3648 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
3651 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
3653 getAutoCreate : function(){
3672 * @class Roo.bootstrap.Modal
3673 * @extends Roo.bootstrap.Component
3674 * Bootstrap Modal class
3675 * @cfg {String} title Title of dialog
3676 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
3677 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
3678 * @cfg {Boolean} specificTitle default false
3679 * @cfg {Array} buttons Array of buttons or standard button set..
3680 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
3681 * @cfg {Boolean} animate default true
3682 * @cfg {Boolean} allow_close default true
3683 * @cfg {Boolean} fitwindow default false
3684 * @cfg {Number} width fixed width - usefull for chrome extension only really.
3685 * @cfg {Number} height fixed height - usefull for chrome extension only really.
3686 * @cfg {String} size (sm|lg) default empty
3687 * @cfg {Number} max_width set the max width of modal
3691 * Create a new Modal Dialog
3692 * @param {Object} config The config object
3695 Roo.bootstrap.Modal = function(config){
3696 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
3701 * The raw btnclick event for the button
3702 * @param {Roo.EventObject} e
3707 * Fire when dialog resize
3708 * @param {Roo.bootstrap.Modal} this
3709 * @param {Roo.EventObject} e
3713 this.buttons = this.buttons || [];
3716 this.tmpl = Roo.factory(this.tmpl);
3721 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
3723 title : 'test dialog',
3733 specificTitle: false,
3735 buttonPosition: 'right',
3758 onRender : function(ct, position)
3760 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
3763 var cfg = Roo.apply({}, this.getAutoCreate());
3766 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
3768 //if (!cfg.name.length) {
3772 cfg.cls += ' ' + this.cls;
3775 cfg.style = this.style;
3777 this.el = Roo.get(document.body).createChild(cfg, position);
3779 //var type = this.el.dom.type;
3782 if(this.tabIndex !== undefined){
3783 this.el.dom.setAttribute('tabIndex', this.tabIndex);
3786 this.dialogEl = this.el.select('.modal-dialog',true).first();
3787 this.bodyEl = this.el.select('.modal-body',true).first();
3788 this.closeEl = this.el.select('.modal-header .close', true).first();
3789 this.headerEl = this.el.select('.modal-header',true).first();
3790 this.titleEl = this.el.select('.modal-title',true).first();
3791 this.footerEl = this.el.select('.modal-footer',true).first();
3793 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
3795 //this.el.addClass("x-dlg-modal");
3797 if (this.buttons.length) {
3798 Roo.each(this.buttons, function(bb) {
3799 var b = Roo.apply({}, bb);
3800 b.xns = b.xns || Roo.bootstrap;
3801 b.xtype = b.xtype || 'Button';
3802 if (typeof(b.listeners) == 'undefined') {
3803 b.listeners = { click : this.onButtonClick.createDelegate(this) };
3806 var btn = Roo.factory(b);
3808 btn.render(this.getButtonContainer());
3812 // render the children.
3815 if(typeof(this.items) != 'undefined'){
3816 var items = this.items;
3819 for(var i =0;i < items.length;i++) {
3820 nitems.push(this.addxtype(Roo.apply({}, items[i])));
3824 this.items = nitems;
3826 // where are these used - they used to be body/close/footer
3830 //this.el.addClass([this.fieldClass, this.cls]);
3834 getAutoCreate : function()
3836 // we will default to modal-body-overflow - might need to remove or make optional later.
3838 cls : 'modal-body enable-modal-body-overflow ',
3839 html : this.html || ''
3844 cls : 'modal-title',
3848 if(this.specificTitle){
3854 if (this.allow_close && Roo.bootstrap.version == 3) {
3864 if (this.allow_close && Roo.bootstrap.version == 4) {
3874 if(this.size.length){
3875 size = 'modal-' + this.size;
3878 var footer = Roo.bootstrap.version == 3 ?
3880 cls : 'modal-footer',
3884 cls: 'btn-' + this.buttonPosition
3889 { // BS4 uses mr-auto on left buttons....
3890 cls : 'modal-footer'
3901 cls: "modal-dialog " + size,
3904 cls : "modal-content",
3907 cls : 'modal-header',
3922 modal.cls += ' fade';
3928 getChildContainer : function() {
3933 getButtonContainer : function() {
3935 return Roo.bootstrap.version == 4 ?
3936 this.el.select('.modal-footer',true).first()
3937 : this.el.select('.modal-footer div',true).first();
3940 initEvents : function()
3942 if (this.allow_close) {
3943 this.closeEl.on('click', this.hide, this);
3945 Roo.EventManager.onWindowResize(this.resize, this, true);
3953 this.maskEl.setSize(
3954 Roo.lib.Dom.getViewWidth(true),
3955 Roo.lib.Dom.getViewHeight(true)
3958 if (this.fitwindow) {
3962 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
3963 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
3968 if(this.max_width !== 0) {
3970 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
3973 this.setSize(w, this.height);
3977 if(this.max_height) {
3978 this.setSize(w,Math.min(
3980 Roo.lib.Dom.getViewportHeight(true) - 60
3986 if(!this.fit_content) {
3987 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
3991 this.setSize(w, Math.min(
3993 this.headerEl.getHeight() +
3994 this.footerEl.getHeight() +
3995 this.getChildHeight(this.bodyEl.dom.childNodes),
3996 Roo.lib.Dom.getViewportHeight(true) - 60)
4002 setSize : function(w,h)
4013 if (!this.rendered) {
4017 //this.el.setStyle('display', 'block');
4018 this.el.removeClass('hideing');
4019 this.el.dom.style.display='block';
4021 Roo.get(document.body).addClass('modal-open');
4023 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
4026 this.el.addClass('show');
4027 this.el.addClass('in');
4030 this.el.addClass('show');
4031 this.el.addClass('in');
4034 // not sure how we can show data in here..
4036 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
4039 Roo.get(document.body).addClass("x-body-masked");
4041 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
4042 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4043 this.maskEl.dom.style.display = 'block';
4044 this.maskEl.addClass('show');
4049 this.fireEvent('show', this);
4051 // set zindex here - otherwise it appears to be ignored...
4052 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4055 this.items.forEach( function(e) {
4056 e.layout ? e.layout() : false;
4064 if(this.fireEvent("beforehide", this) !== false){
4066 this.maskEl.removeClass('show');
4068 this.maskEl.dom.style.display = '';
4069 Roo.get(document.body).removeClass("x-body-masked");
4070 this.el.removeClass('in');
4071 this.el.select('.modal-dialog', true).first().setStyle('transform','');
4073 if(this.animate){ // why
4074 this.el.addClass('hideing');
4075 this.el.removeClass('show');
4077 if (!this.el.hasClass('hideing')) {
4078 return; // it's been shown again...
4081 this.el.dom.style.display='';
4083 Roo.get(document.body).removeClass('modal-open');
4084 this.el.removeClass('hideing');
4088 this.el.removeClass('show');
4089 this.el.dom.style.display='';
4090 Roo.get(document.body).removeClass('modal-open');
4093 this.fireEvent('hide', this);
4096 isVisible : function()
4099 return this.el.hasClass('show') && !this.el.hasClass('hideing');
4103 addButton : function(str, cb)
4107 var b = Roo.apply({}, { html : str } );
4108 b.xns = b.xns || Roo.bootstrap;
4109 b.xtype = b.xtype || 'Button';
4110 if (typeof(b.listeners) == 'undefined') {
4111 b.listeners = { click : cb.createDelegate(this) };
4114 var btn = Roo.factory(b);
4116 btn.render(this.getButtonContainer());
4122 setDefaultButton : function(btn)
4124 //this.el.select('.modal-footer').()
4127 resizeTo: function(w,h)
4129 this.dialogEl.setWidth(w);
4131 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
4133 this.bodyEl.setHeight(h - diff);
4135 this.fireEvent('resize', this);
4138 setContentSize : function(w, h)
4142 onButtonClick: function(btn,e)
4145 this.fireEvent('btnclick', btn.name, e);
4148 * Set the title of the Dialog
4149 * @param {String} str new Title
4151 setTitle: function(str) {
4152 this.titleEl.dom.innerHTML = str;
4155 * Set the body of the Dialog
4156 * @param {String} str new Title
4158 setBody: function(str) {
4159 this.bodyEl.dom.innerHTML = str;
4162 * Set the body of the Dialog using the template
4163 * @param {Obj} data - apply this data to the template and replace the body contents.
4165 applyBody: function(obj)
4168 Roo.log("Error - using apply Body without a template");
4171 this.tmpl.overwrite(this.bodyEl, obj);
4174 getChildHeight : function(child_nodes)
4178 child_nodes.length == 0
4183 var child_height = 0;
4185 for(var i = 0; i < child_nodes.length; i++) {
4188 * for modal with tabs...
4189 if(child_nodes[i].classList.contains('roo-layout-panel')) {
4191 var layout_childs = child_nodes[i].childNodes;
4193 for(var j = 0; j < layout_childs.length; j++) {
4195 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
4197 var layout_body_childs = layout_childs[j].childNodes;
4199 for(var k = 0; k < layout_body_childs.length; k++) {
4201 if(layout_body_childs[k].classList.contains('navbar')) {
4202 child_height += layout_body_childs[k].offsetHeight;
4206 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
4208 var layout_body_tab_childs = layout_body_childs[k].childNodes;
4210 for(var m = 0; m < layout_body_tab_childs.length; m++) {
4212 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
4213 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
4228 child_height += child_nodes[i].offsetHeight;
4229 // Roo.log(child_nodes[i].offsetHeight);
4232 return child_height;
4238 Roo.apply(Roo.bootstrap.Modal, {
4240 * Button config that displays a single OK button
4249 * Button config that displays Yes and No buttons
4265 * Button config that displays OK and Cancel buttons
4280 * Button config that displays Yes, No and Cancel buttons
4304 * messagebox - can be used as a replace
4308 * @class Roo.MessageBox
4309 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
4313 Roo.Msg.alert('Status', 'Changes saved successfully.');
4315 // Prompt for user data:
4316 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
4318 // process text value...
4322 // Show a dialog using config options:
4324 title:'Save Changes?',
4325 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
4326 buttons: Roo.Msg.YESNOCANCEL,
4333 Roo.bootstrap.MessageBox = function(){
4334 var dlg, opt, mask, waitTimer;
4335 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
4336 var buttons, activeTextEl, bwidth;
4340 var handleButton = function(button){
4342 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
4346 var handleHide = function(){
4348 dlg.el.removeClass(opt.cls);
4351 // Roo.TaskMgr.stop(waitTimer);
4352 // waitTimer = null;
4357 var updateButtons = function(b){
4360 buttons["ok"].hide();
4361 buttons["cancel"].hide();
4362 buttons["yes"].hide();
4363 buttons["no"].hide();
4364 dlg.footerEl.hide();
4368 dlg.footerEl.show();
4369 for(var k in buttons){
4370 if(typeof buttons[k] != "function"){
4373 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
4374 width += buttons[k].el.getWidth()+15;
4384 var handleEsc = function(d, k, e){
4385 if(opt && opt.closable !== false){
4395 * Returns a reference to the underlying {@link Roo.BasicDialog} element
4396 * @return {Roo.BasicDialog} The BasicDialog element
4398 getDialog : function(){
4400 dlg = new Roo.bootstrap.Modal( {
4403 //constraintoviewport:false,
4405 //collapsible : false,
4410 //buttonAlign:"center",
4411 closeClick : function(){
4412 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
4415 handleButton("cancel");
4420 dlg.on("hide", handleHide);
4422 //dlg.addKeyListener(27, handleEsc);
4424 this.buttons = buttons;
4425 var bt = this.buttonText;
4426 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
4427 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
4428 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
4429 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
4431 bodyEl = dlg.bodyEl.createChild({
4433 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
4434 '<textarea class="roo-mb-textarea"></textarea>' +
4435 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
4437 msgEl = bodyEl.dom.firstChild;
4438 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
4439 textboxEl.enableDisplayMode();
4440 textboxEl.addKeyListener([10,13], function(){
4441 if(dlg.isVisible() && opt && opt.buttons){
4444 }else if(opt.buttons.yes){
4445 handleButton("yes");
4449 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
4450 textareaEl.enableDisplayMode();
4451 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
4452 progressEl.enableDisplayMode();
4454 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
4455 var pf = progressEl.dom.firstChild;
4457 pp = Roo.get(pf.firstChild);
4458 pp.setHeight(pf.offsetHeight);
4466 * Updates the message box body text
4467 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
4468 * the XHTML-compliant non-breaking space character '&#160;')
4469 * @return {Roo.MessageBox} This message box
4471 updateText : function(text)
4473 if(!dlg.isVisible() && !opt.width){
4474 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
4475 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
4477 msgEl.innerHTML = text || ' ';
4479 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
4480 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
4482 Math.min(opt.width || cw , this.maxWidth),
4483 Math.max(opt.minWidth || this.minWidth, bwidth)
4486 activeTextEl.setWidth(w);
4488 if(dlg.isVisible()){
4489 dlg.fixedcenter = false;
4491 // to big, make it scroll. = But as usual stupid IE does not support
4494 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
4495 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
4496 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
4498 bodyEl.dom.style.height = '';
4499 bodyEl.dom.style.overflowY = '';
4502 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
4504 bodyEl.dom.style.overflowX = '';
4507 dlg.setContentSize(w, bodyEl.getHeight());
4508 if(dlg.isVisible()){
4509 dlg.fixedcenter = true;
4515 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
4516 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
4517 * @param {Number} value Any number between 0 and 1 (e.g., .5)
4518 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
4519 * @return {Roo.MessageBox} This message box
4521 updateProgress : function(value, text){
4523 this.updateText(text);
4526 if (pp) { // weird bug on my firefox - for some reason this is not defined
4527 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
4528 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
4534 * Returns true if the message box is currently displayed
4535 * @return {Boolean} True if the message box is visible, else false
4537 isVisible : function(){
4538 return dlg && dlg.isVisible();
4542 * Hides the message box if it is displayed
4545 if(this.isVisible()){
4551 * Displays a new message box, or reinitializes an existing message box, based on the config options
4552 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
4553 * The following config object properties are supported:
4555 Property Type Description
4556 ---------- --------------- ------------------------------------------------------------------------------------
4557 animEl String/Element An id or Element from which the message box should animate as it opens and
4558 closes (defaults to undefined)
4559 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
4560 cancel:'Bar'}), or false to not show any buttons (defaults to false)
4561 closable Boolean False to hide the top-right close button (defaults to true). Note that
4562 progress and wait dialogs will ignore this property and always hide the
4563 close button as they can only be closed programmatically.
4564 cls String A custom CSS class to apply to the message box element
4565 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
4566 displayed (defaults to 75)
4567 fn Function A callback function to execute after closing the dialog. The arguments to the
4568 function will be btn (the name of the button that was clicked, if applicable,
4569 e.g. "ok"), and text (the value of the active text field, if applicable).
4570 Progress and wait dialogs will ignore this option since they do not respond to
4571 user actions and can only be closed programmatically, so any required function
4572 should be called by the same code after it closes the dialog.
4573 icon String A CSS class that provides a background image to be used as an icon for
4574 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
4575 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
4576 minWidth Number The minimum width in pixels of the message box (defaults to 100)
4577 modal Boolean False to allow user interaction with the page while the message box is
4578 displayed (defaults to true)
4579 msg String A string that will replace the existing message box body text (defaults
4580 to the XHTML-compliant non-breaking space character ' ')
4581 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
4582 progress Boolean True to display a progress bar (defaults to false)
4583 progressText String The text to display inside the progress bar if progress = true (defaults to '')
4584 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
4585 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
4586 title String The title text
4587 value String The string value to set into the active textbox element if displayed
4588 wait Boolean True to display a progress bar (defaults to false)
4589 width Number The width of the dialog in pixels
4596 msg: 'Please enter your address:',
4598 buttons: Roo.MessageBox.OKCANCEL,
4601 animEl: 'addAddressBtn'
4604 * @param {Object} config Configuration options
4605 * @return {Roo.MessageBox} This message box
4607 show : function(options)
4610 // this causes nightmares if you show one dialog after another
4611 // especially on callbacks..
4613 if(this.isVisible()){
4616 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
4617 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
4618 Roo.log("New Dialog Message:" + options.msg )
4619 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
4620 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
4623 var d = this.getDialog();
4625 d.setTitle(opt.title || " ");
4626 d.closeEl.setDisplayed(opt.closable !== false);
4627 activeTextEl = textboxEl;
4628 opt.prompt = opt.prompt || (opt.multiline ? true : false);
4633 textareaEl.setHeight(typeof opt.multiline == "number" ?
4634 opt.multiline : this.defaultTextHeight);
4635 activeTextEl = textareaEl;
4644 progressEl.setDisplayed(opt.progress === true);
4646 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
4648 this.updateProgress(0);
4649 activeTextEl.dom.value = opt.value || "";
4651 dlg.setDefaultButton(activeTextEl);
4653 var bs = opt.buttons;
4657 }else if(bs && bs.yes){
4658 db = buttons["yes"];
4660 dlg.setDefaultButton(db);
4662 bwidth = updateButtons(opt.buttons);
4663 this.updateText(opt.msg);
4665 d.el.addClass(opt.cls);
4667 d.proxyDrag = opt.proxyDrag === true;
4668 d.modal = opt.modal !== false;
4669 d.mask = opt.modal !== false ? mask : false;
4671 // force it to the end of the z-index stack so it gets a cursor in FF
4672 document.body.appendChild(dlg.el.dom);
4673 d.animateTarget = null;
4674 d.show(options.animEl);
4680 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
4681 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
4682 * and closing the message box when the process is complete.
4683 * @param {String} title The title bar text
4684 * @param {String} msg The message box body text
4685 * @return {Roo.MessageBox} This message box
4687 progress : function(title, msg){
4694 minWidth: this.minProgressWidth,
4701 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
4702 * If a callback function is passed it will be called after the user clicks the button, and the
4703 * id of the button that was clicked will be passed as the only parameter to the callback
4704 * (could also be the top-right close button).
4705 * @param {String} title The title bar text
4706 * @param {String} msg The message box body text
4707 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4708 * @param {Object} scope (optional) The scope of the callback function
4709 * @return {Roo.MessageBox} This message box
4711 alert : function(title, msg, fn, scope)
4726 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
4727 * interaction while waiting for a long-running process to complete that does not have defined intervals.
4728 * You are responsible for closing the message box when the process is complete.
4729 * @param {String} msg The message box body text
4730 * @param {String} title (optional) The title bar text
4731 * @return {Roo.MessageBox} This message box
4733 wait : function(msg, title){
4744 waitTimer = Roo.TaskMgr.start({
4746 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
4754 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
4755 * If a callback function is passed it will be called after the user clicks either button, and the id of the
4756 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
4757 * @param {String} title The title bar text
4758 * @param {String} msg The message box body text
4759 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4760 * @param {Object} scope (optional) The scope of the callback function
4761 * @return {Roo.MessageBox} This message box
4763 confirm : function(title, msg, fn, scope){
4767 buttons: this.YESNO,
4776 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
4777 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
4778 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
4779 * (could also be the top-right close button) and the text that was entered will be passed as the two
4780 * parameters to the callback.
4781 * @param {String} title The title bar text
4782 * @param {String} msg The message box body text
4783 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4784 * @param {Object} scope (optional) The scope of the callback function
4785 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
4786 * property, or the height in pixels to create the textbox (defaults to false / single-line)
4787 * @return {Roo.MessageBox} This message box
4789 prompt : function(title, msg, fn, scope, multiline){
4793 buttons: this.OKCANCEL,
4798 multiline: multiline,
4805 * Button config that displays a single OK button
4810 * Button config that displays Yes and No buttons
4813 YESNO : {yes:true, no:true},
4815 * Button config that displays OK and Cancel buttons
4818 OKCANCEL : {ok:true, cancel:true},
4820 * Button config that displays Yes, No and Cancel buttons
4823 YESNOCANCEL : {yes:true, no:true, cancel:true},
4826 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
4829 defaultTextHeight : 75,
4831 * The maximum width in pixels of the message box (defaults to 600)
4836 * The minimum width in pixels of the message box (defaults to 100)
4841 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
4842 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
4845 minProgressWidth : 250,
4847 * An object containing the default button text strings that can be overriden for localized language support.
4848 * Supported properties are: ok, cancel, yes and no.
4849 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
4862 * Shorthand for {@link Roo.MessageBox}
4864 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
4865 Roo.Msg = Roo.Msg || Roo.MessageBox;
4874 * @class Roo.bootstrap.Navbar
4875 * @extends Roo.bootstrap.Component
4876 * Bootstrap Navbar class
4879 * Create a new Navbar
4880 * @param {Object} config The config object
4884 Roo.bootstrap.Navbar = function(config){
4885 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
4889 * @event beforetoggle
4890 * Fire before toggle the menu
4891 * @param {Roo.EventObject} e
4893 "beforetoggle" : true
4897 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
4906 getAutoCreate : function(){
4909 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
4913 initEvents :function ()
4915 //Roo.log(this.el.select('.navbar-toggle',true));
4916 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
4923 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
4925 var size = this.el.getSize();
4926 this.maskEl.setSize(size.width, size.height);
4927 this.maskEl.enableDisplayMode("block");
4936 getChildContainer : function()
4938 if (this.el && this.el.select('.collapse').getCount()) {
4939 return this.el.select('.collapse',true).first();
4954 onToggle : function()
4957 if(this.fireEvent('beforetoggle', this) === false){
4960 var ce = this.el.select('.navbar-collapse',true).first();
4962 if (!ce.hasClass('show')) {
4972 * Expand the navbar pulldown
4974 expand : function ()
4977 var ce = this.el.select('.navbar-collapse',true).first();
4978 if (ce.hasClass('collapsing')) {
4981 ce.dom.style.height = '';
4983 ce.addClass('in'); // old...
4984 ce.removeClass('collapse');
4985 ce.addClass('show');
4986 var h = ce.getHeight();
4988 ce.removeClass('show');
4989 // at this point we should be able to see it..
4990 ce.addClass('collapsing');
4992 ce.setHeight(0); // resize it ...
4993 ce.on('transitionend', function() {
4994 //Roo.log('done transition');
4995 ce.removeClass('collapsing');
4996 ce.addClass('show');
4997 ce.removeClass('collapse');
4999 ce.dom.style.height = '';
5000 }, this, { single: true} );
5002 ce.dom.scrollTop = 0;
5005 * Collapse the navbar pulldown
5007 collapse : function()
5009 var ce = this.el.select('.navbar-collapse',true).first();
5011 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
5012 // it's collapsed or collapsing..
5015 ce.removeClass('in'); // old...
5016 ce.setHeight(ce.getHeight());
5017 ce.removeClass('show');
5018 ce.addClass('collapsing');
5020 ce.on('transitionend', function() {
5021 ce.dom.style.height = '';
5022 ce.removeClass('collapsing');
5023 ce.addClass('collapse');
5024 }, this, { single: true} );
5044 * @class Roo.bootstrap.NavSimplebar
5045 * @extends Roo.bootstrap.Navbar
5046 * Bootstrap Sidebar class
5048 * @cfg {Boolean} inverse is inverted color
5050 * @cfg {String} type (nav | pills | tabs)
5051 * @cfg {Boolean} arrangement stacked | justified
5052 * @cfg {String} align (left | right) alignment
5054 * @cfg {Boolean} main (true|false) main nav bar? default false
5055 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
5057 * @cfg {String} tag (header|footer|nav|div) default is nav
5059 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
5063 * Create a new Sidebar
5064 * @param {Object} config The config object
5068 Roo.bootstrap.NavSimplebar = function(config){
5069 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
5072 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
5088 getAutoCreate : function(){
5092 tag : this.tag || 'div',
5093 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
5095 if (['light','white'].indexOf(this.weight) > -1) {
5096 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5098 cfg.cls += ' bg-' + this.weight;
5101 cfg.cls += ' navbar-inverse';
5105 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
5107 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
5116 cls: 'nav nav-' + this.xtype,
5122 this.type = this.type || 'nav';
5123 if (['tabs','pills'].indexOf(this.type) != -1) {
5124 cfg.cn[0].cls += ' nav-' + this.type
5128 if (this.type!=='nav') {
5129 Roo.log('nav type must be nav/tabs/pills')
5131 cfg.cn[0].cls += ' navbar-nav'
5137 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
5138 cfg.cn[0].cls += ' nav-' + this.arrangement;
5142 if (this.align === 'right') {
5143 cfg.cn[0].cls += ' navbar-right';
5168 * navbar-expand-md fixed-top
5172 * @class Roo.bootstrap.NavHeaderbar
5173 * @extends Roo.bootstrap.NavSimplebar
5174 * Bootstrap Sidebar class
5176 * @cfg {String} brand what is brand
5177 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
5178 * @cfg {String} brand_href href of the brand
5179 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
5180 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
5181 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
5182 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
5185 * Create a new Sidebar
5186 * @param {Object} config The config object
5190 Roo.bootstrap.NavHeaderbar = function(config){
5191 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
5195 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
5202 desktopCenter : false,
5205 getAutoCreate : function(){
5208 tag: this.nav || 'nav',
5209 cls: 'navbar navbar-expand-md',
5215 if (this.desktopCenter) {
5216 cn.push({cls : 'container', cn : []});
5224 cls: 'navbar-toggle navbar-toggler',
5225 'data-toggle': 'collapse',
5230 html: 'Toggle navigation'
5234 cls: 'icon-bar navbar-toggler-icon'
5247 cn.push( Roo.bootstrap.version == 4 ? btn : {
5249 cls: 'navbar-header',
5258 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse collapse navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
5262 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
5264 if (['light','white'].indexOf(this.weight) > -1) {
5265 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5267 cfg.cls += ' bg-' + this.weight;
5270 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
5271 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
5273 // tag can override this..
5275 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
5278 if (this.brand !== '') {
5279 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
5280 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
5282 href: this.brand_href ? this.brand_href : '#',
5283 cls: 'navbar-brand',
5291 cfg.cls += ' main-nav';
5299 getHeaderChildContainer : function()
5301 if (this.srButton && this.el.select('.navbar-header').getCount()) {
5302 return this.el.select('.navbar-header',true).first();
5305 return this.getChildContainer();
5308 getChildContainer : function()
5311 return this.el.select('.roo-navbar-collapse',true).first();
5316 initEvents : function()
5318 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
5320 if (this.autohide) {
5325 Roo.get(document).on('scroll',function(e) {
5326 var ns = Roo.get(document).getScroll().top;
5327 var os = prevScroll;
5331 ft.removeClass('slideDown');
5332 ft.addClass('slideUp');
5335 ft.removeClass('slideUp');
5336 ft.addClass('slideDown');
5357 * @class Roo.bootstrap.NavSidebar
5358 * @extends Roo.bootstrap.Navbar
5359 * Bootstrap Sidebar class
5362 * Create a new Sidebar
5363 * @param {Object} config The config object
5367 Roo.bootstrap.NavSidebar = function(config){
5368 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
5371 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
5373 sidebar : true, // used by Navbar Item and NavbarGroup at present...
5375 getAutoCreate : function(){
5380 cls: 'sidebar sidebar-nav'
5402 * @class Roo.bootstrap.NavGroup
5403 * @extends Roo.bootstrap.Component
5404 * Bootstrap NavGroup class
5405 * @cfg {String} align (left|right)
5406 * @cfg {Boolean} inverse
5407 * @cfg {String} type (nav|pills|tab) default nav
5408 * @cfg {String} navId - reference Id for navbar.
5412 * Create a new nav group
5413 * @param {Object} config The config object
5416 Roo.bootstrap.NavGroup = function(config){
5417 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
5420 Roo.bootstrap.NavGroup.register(this);
5424 * Fires when the active item changes
5425 * @param {Roo.bootstrap.NavGroup} this
5426 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
5427 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
5434 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
5445 getAutoCreate : function()
5447 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
5453 if (Roo.bootstrap.version == 4) {
5454 if (['tabs','pills'].indexOf(this.type) != -1) {
5455 cfg.cls += ' nav-' + this.type;
5457 // trying to remove so header bar can right align top?
5458 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
5459 // do not use on header bar...
5460 cfg.cls += ' navbar-nav';
5465 if (['tabs','pills'].indexOf(this.type) != -1) {
5466 cfg.cls += ' nav-' + this.type
5468 if (this.type !== 'nav') {
5469 Roo.log('nav type must be nav/tabs/pills')
5471 cfg.cls += ' navbar-nav'
5475 if (this.parent() && this.parent().sidebar) {
5478 cls: 'dashboard-menu sidebar-menu'
5484 if (this.form === true) {
5487 cls: 'navbar-form form-inline'
5489 //nav navbar-right ml-md-auto
5490 if (this.align === 'right') {
5491 cfg.cls += ' navbar-right ml-md-auto';
5493 cfg.cls += ' navbar-left';
5497 if (this.align === 'right') {
5498 cfg.cls += ' navbar-right ml-md-auto';
5500 cfg.cls += ' mr-auto';
5504 cfg.cls += ' navbar-inverse';
5512 * sets the active Navigation item
5513 * @param {Roo.bootstrap.NavItem} the new current navitem
5515 setActiveItem : function(item)
5518 Roo.each(this.navItems, function(v){
5523 v.setActive(false, true);
5530 item.setActive(true, true);
5531 this.fireEvent('changed', this, item, prev);
5536 * gets the active Navigation item
5537 * @return {Roo.bootstrap.NavItem} the current navitem
5539 getActive : function()
5543 Roo.each(this.navItems, function(v){
5554 indexOfNav : function()
5558 Roo.each(this.navItems, function(v,i){
5569 * adds a Navigation item
5570 * @param {Roo.bootstrap.NavItem} the navitem to add
5572 addItem : function(cfg)
5574 if (this.form && Roo.bootstrap.version == 4) {
5577 var cn = new Roo.bootstrap.NavItem(cfg);
5579 cn.parentId = this.id;
5580 cn.onRender(this.el, null);
5584 * register a Navigation item
5585 * @param {Roo.bootstrap.NavItem} the navitem to add
5587 register : function(item)
5589 this.navItems.push( item);
5590 item.navId = this.navId;
5595 * clear all the Navigation item
5598 clearAll : function()
5601 this.el.dom.innerHTML = '';
5604 getNavItem: function(tabId)
5607 Roo.each(this.navItems, function(e) {
5608 if (e.tabId == tabId) {
5618 setActiveNext : function()
5620 var i = this.indexOfNav(this.getActive());
5621 if (i > this.navItems.length) {
5624 this.setActiveItem(this.navItems[i+1]);
5626 setActivePrev : function()
5628 var i = this.indexOfNav(this.getActive());
5632 this.setActiveItem(this.navItems[i-1]);
5634 clearWasActive : function(except) {
5635 Roo.each(this.navItems, function(e) {
5636 if (e.tabId != except.tabId && e.was_active) {
5637 e.was_active = false;
5644 getWasActive : function ()
5647 Roo.each(this.navItems, function(e) {
5662 Roo.apply(Roo.bootstrap.NavGroup, {
5666 * register a Navigation Group
5667 * @param {Roo.bootstrap.NavGroup} the navgroup to add
5669 register : function(navgrp)
5671 this.groups[navgrp.navId] = navgrp;
5675 * fetch a Navigation Group based on the navigation ID
5676 * @param {string} the navgroup to add
5677 * @returns {Roo.bootstrap.NavGroup} the navgroup
5679 get: function(navId) {
5680 if (typeof(this.groups[navId]) == 'undefined') {
5682 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
5684 return this.groups[navId] ;
5699 * @class Roo.bootstrap.NavItem
5700 * @extends Roo.bootstrap.Component
5701 * Bootstrap Navbar.NavItem class
5702 * @cfg {String} href link to
5703 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
5705 * @cfg {String} html content of button
5706 * @cfg {String} badge text inside badge
5707 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
5708 * @cfg {String} glyphicon DEPRICATED - use fa
5709 * @cfg {String} icon DEPRICATED - use fa
5710 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
5711 * @cfg {Boolean} active Is item active
5712 * @cfg {Boolean} disabled Is item disabled
5714 * @cfg {Boolean} preventDefault (true | false) default false
5715 * @cfg {String} tabId the tab that this item activates.
5716 * @cfg {String} tagtype (a|span) render as a href or span?
5717 * @cfg {Boolean} animateRef (true|false) link to element default false
5720 * Create a new Navbar Item
5721 * @param {Object} config The config object
5723 Roo.bootstrap.NavItem = function(config){
5724 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
5729 * The raw click event for the entire grid.
5730 * @param {Roo.EventObject} e
5735 * Fires when the active item active state changes
5736 * @param {Roo.bootstrap.NavItem} this
5737 * @param {boolean} state the new state
5743 * Fires when scroll to element
5744 * @param {Roo.bootstrap.NavItem} this
5745 * @param {Object} options
5746 * @param {Roo.EventObject} e
5754 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
5763 preventDefault : false,
5771 button_outline : false,
5775 getAutoCreate : function(){
5783 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
5785 if (this.disabled) {
5786 cfg.cls += ' disabled';
5790 if (this.button_weight.length) {
5791 cfg.tag = this.href ? 'a' : 'button';
5792 cfg.html = this.html || '';
5793 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
5795 cfg.href = this.href;
5798 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
5801 // menu .. should add dropdown-menu class - so no need for carat..
5803 if (this.badge !== '') {
5805 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
5810 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
5814 href : this.href || "#",
5815 html: this.html || ''
5818 if (this.tagtype == 'a') {
5819 cfg.cn[0].cls = 'nav-link';
5822 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
5825 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
5827 if(this.glyphicon) {
5828 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
5833 cfg.cn[0].html += " <span class='caret'></span>";
5837 if (this.badge !== '') {
5839 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
5847 onRender : function(ct, position)
5849 // Roo.log("Call onRender: " + this.xtype);
5850 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
5854 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
5855 this.navLink = this.el.select('.nav-link',true).first();
5860 initEvents: function()
5862 if (typeof (this.menu) != 'undefined') {
5863 this.menu.parentType = this.xtype;
5864 this.menu.triggerEl = this.el;
5865 this.menu = this.addxtype(Roo.apply({}, this.menu));
5868 this.el.select('a',true).on('click', this.onClick, this);
5870 if(this.tagtype == 'span'){
5871 this.el.select('span',true).on('click', this.onClick, this);
5874 // at this point parent should be available..
5875 this.parent().register(this);
5878 onClick : function(e)
5880 if (e.getTarget('.dropdown-menu-item')) {
5881 // did you click on a menu itemm.... - then don't trigger onclick..
5886 this.preventDefault ||
5889 Roo.log("NavItem - prevent Default?");
5893 if (this.disabled) {
5897 var tg = Roo.bootstrap.TabGroup.get(this.navId);
5898 if (tg && tg.transition) {
5899 Roo.log("waiting for the transitionend");
5905 //Roo.log("fire event clicked");
5906 if(this.fireEvent('click', this, e) === false){
5910 if(this.tagtype == 'span'){
5914 //Roo.log(this.href);
5915 var ael = this.el.select('a',true).first();
5918 if(ael && this.animateRef && this.href.indexOf('#') > -1){
5919 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
5920 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
5921 return; // ignore... - it's a 'hash' to another page.
5923 Roo.log("NavItem - prevent Default?");
5925 this.scrollToElement(e);
5929 var p = this.parent();
5931 if (['tabs','pills'].indexOf(p.type)!==-1) {
5932 if (typeof(p.setActiveItem) !== 'undefined') {
5933 p.setActiveItem(this);
5937 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
5938 if (p.parentType == 'NavHeaderbar' && !this.menu) {
5939 // remove the collapsed menu expand...
5940 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
5944 isActive: function () {
5947 setActive : function(state, fire, is_was_active)
5949 if (this.active && !state && this.navId) {
5950 this.was_active = true;
5951 var nv = Roo.bootstrap.NavGroup.get(this.navId);
5953 nv.clearWasActive(this);
5957 this.active = state;
5960 this.el.removeClass('active');
5961 this.navLink ? this.navLink.removeClass('active') : false;
5962 } else if (!this.el.hasClass('active')) {
5964 this.el.addClass('active');
5965 if (Roo.bootstrap.version == 4 && this.navLink ) {
5966 this.navLink.addClass('active');
5971 this.fireEvent('changed', this, state);
5974 // show a panel if it's registered and related..
5976 if (!this.navId || !this.tabId || !state || is_was_active) {
5980 var tg = Roo.bootstrap.TabGroup.get(this.navId);
5984 var pan = tg.getPanelByName(this.tabId);
5988 // if we can not flip to new panel - go back to old nav highlight..
5989 if (false == tg.showPanel(pan)) {
5990 var nv = Roo.bootstrap.NavGroup.get(this.navId);
5992 var onav = nv.getWasActive();
5994 onav.setActive(true, false, true);
6003 // this should not be here...
6004 setDisabled : function(state)
6006 this.disabled = state;
6008 this.el.removeClass('disabled');
6009 } else if (!this.el.hasClass('disabled')) {
6010 this.el.addClass('disabled');
6016 * Fetch the element to display the tooltip on.
6017 * @return {Roo.Element} defaults to this.el
6019 tooltipEl : function()
6021 return this.el.select('' + this.tagtype + '', true).first();
6024 scrollToElement : function(e)
6026 var c = document.body;
6029 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
6031 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
6032 c = document.documentElement;
6035 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
6041 var o = target.calcOffsetsTo(c);
6048 this.fireEvent('scrollto', this, options, e);
6050 Roo.get(c).scrollTo('top', options.value, true);
6063 * <span> icon </span>
6064 * <span> text </span>
6065 * <span>badge </span>
6069 * @class Roo.bootstrap.NavSidebarItem
6070 * @extends Roo.bootstrap.NavItem
6071 * Bootstrap Navbar.NavSidebarItem class
6072 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
6073 * {Boolean} open is the menu open
6074 * {Boolean} buttonView use button as the tigger el rather that a (default false)
6075 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
6076 * {String} buttonSize (sm|md|lg)the extra classes for the button
6077 * {Boolean} showArrow show arrow next to the text (default true)
6079 * Create a new Navbar Button
6080 * @param {Object} config The config object
6082 Roo.bootstrap.NavSidebarItem = function(config){
6083 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
6088 * The raw click event for the entire grid.
6089 * @param {Roo.EventObject} e
6094 * Fires when the active item active state changes
6095 * @param {Roo.bootstrap.NavSidebarItem} this
6096 * @param {boolean} state the new state
6104 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
6106 badgeWeight : 'default',
6112 buttonWeight : 'default',
6118 getAutoCreate : function(){
6123 href : this.href || '#',
6129 if(this.buttonView){
6132 href : this.href || '#',
6133 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
6146 cfg.cls += ' active';
6149 if (this.disabled) {
6150 cfg.cls += ' disabled';
6153 cfg.cls += ' open x-open';
6156 if (this.glyphicon || this.icon) {
6157 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
6158 a.cn.push({ tag : 'i', cls : c }) ;
6161 if(!this.buttonView){
6164 html : this.html || ''
6171 if (this.badge !== '') {
6172 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
6178 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
6181 a.cls += ' dropdown-toggle treeview' ;
6187 initEvents : function()
6189 if (typeof (this.menu) != 'undefined') {
6190 this.menu.parentType = this.xtype;
6191 this.menu.triggerEl = this.el;
6192 this.menu = this.addxtype(Roo.apply({}, this.menu));
6195 this.el.on('click', this.onClick, this);
6197 if(this.badge !== ''){
6198 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
6203 onClick : function(e)
6210 if(this.preventDefault){
6214 this.fireEvent('click', this, e);
6217 disable : function()
6219 this.setDisabled(true);
6224 this.setDisabled(false);
6227 setDisabled : function(state)
6229 if(this.disabled == state){
6233 this.disabled = state;
6236 this.el.addClass('disabled');
6240 this.el.removeClass('disabled');
6245 setActive : function(state)
6247 if(this.active == state){
6251 this.active = state;
6254 this.el.addClass('active');
6258 this.el.removeClass('active');
6263 isActive: function ()
6268 setBadge : function(str)
6274 this.badgeEl.dom.innerHTML = str;
6291 * @class Roo.bootstrap.Row
6292 * @extends Roo.bootstrap.Component
6293 * Bootstrap Row class (contains columns...)
6297 * @param {Object} config The config object
6300 Roo.bootstrap.Row = function(config){
6301 Roo.bootstrap.Row.superclass.constructor.call(this, config);
6304 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
6306 getAutoCreate : function(){
6325 * @class Roo.bootstrap.Pagination
6326 * @extends Roo.bootstrap.Component
6327 * Bootstrap Pagination class
6328 * @cfg {String} size xs | sm | md | lg
6329 * @cfg {Boolean} inverse false | true
6332 * Create a new Pagination
6333 * @param {Object} config The config object
6336 Roo.bootstrap.Pagination = function(config){
6337 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
6340 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
6346 getAutoCreate : function(){
6352 cfg.cls += ' inverse';
6358 cfg.cls += " " + this.cls;
6376 * @class Roo.bootstrap.PaginationItem
6377 * @extends Roo.bootstrap.Component
6378 * Bootstrap PaginationItem class
6379 * @cfg {String} html text
6380 * @cfg {String} href the link
6381 * @cfg {Boolean} preventDefault (true | false) default true
6382 * @cfg {Boolean} active (true | false) default false
6383 * @cfg {Boolean} disabled default false
6387 * Create a new PaginationItem
6388 * @param {Object} config The config object
6392 Roo.bootstrap.PaginationItem = function(config){
6393 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
6398 * The raw click event for the entire grid.
6399 * @param {Roo.EventObject} e
6405 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
6409 preventDefault: true,
6414 getAutoCreate : function(){
6420 href : this.href ? this.href : '#',
6421 html : this.html ? this.html : ''
6431 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
6435 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
6441 initEvents: function() {
6443 this.el.on('click', this.onClick, this);
6446 onClick : function(e)
6448 Roo.log('PaginationItem on click ');
6449 if(this.preventDefault){
6457 this.fireEvent('click', this, e);
6473 * @class Roo.bootstrap.Slider
6474 * @extends Roo.bootstrap.Component
6475 * Bootstrap Slider class
6478 * Create a new Slider
6479 * @param {Object} config The config object
6482 Roo.bootstrap.Slider = function(config){
6483 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
6486 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
6488 getAutoCreate : function(){
6492 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
6496 cls: 'ui-slider-handle ui-state-default ui-corner-all'
6508 * Ext JS Library 1.1.1
6509 * Copyright(c) 2006-2007, Ext JS, LLC.
6511 * Originally Released Under LGPL - original licence link has changed is not relivant.
6514 * <script type="text/javascript">
6519 * @class Roo.grid.ColumnModel
6520 * @extends Roo.util.Observable
6521 * This is the default implementation of a ColumnModel used by the Grid. It defines
6522 * the columns in the grid.
6525 var colModel = new Roo.grid.ColumnModel([
6526 {header: "Ticker", width: 60, sortable: true, locked: true},
6527 {header: "Company Name", width: 150, sortable: true},
6528 {header: "Market Cap.", width: 100, sortable: true},
6529 {header: "$ Sales", width: 100, sortable: true, renderer: money},
6530 {header: "Employees", width: 100, sortable: true, resizable: false}
6535 * The config options listed for this class are options which may appear in each
6536 * individual column definition.
6537 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
6539 * @param {Object} config An Array of column config objects. See this class's
6540 * config objects for details.
6542 Roo.grid.ColumnModel = function(config){
6544 * The config passed into the constructor
6546 this.config = config;
6549 // if no id, create one
6550 // if the column does not have a dataIndex mapping,
6551 // map it to the order it is in the config
6552 for(var i = 0, len = config.length; i < len; i++){
6554 if(typeof c.dataIndex == "undefined"){
6557 if(typeof c.renderer == "string"){
6558 c.renderer = Roo.util.Format[c.renderer];
6560 if(typeof c.id == "undefined"){
6563 if(c.editor && c.editor.xtype){
6564 c.editor = Roo.factory(c.editor, Roo.grid);
6566 if(c.editor && c.editor.isFormField){
6567 c.editor = new Roo.grid.GridEditor(c.editor);
6569 this.lookup[c.id] = c;
6573 * The width of columns which have no width specified (defaults to 100)
6576 this.defaultWidth = 100;
6579 * Default sortable of columns which have no sortable specified (defaults to false)
6582 this.defaultSortable = false;
6586 * @event widthchange
6587 * Fires when the width of a column changes.
6588 * @param {ColumnModel} this
6589 * @param {Number} columnIndex The column index
6590 * @param {Number} newWidth The new width
6592 "widthchange": true,
6594 * @event headerchange
6595 * Fires when the text of a header changes.
6596 * @param {ColumnModel} this
6597 * @param {Number} columnIndex The column index
6598 * @param {Number} newText The new header text
6600 "headerchange": true,
6602 * @event hiddenchange
6603 * Fires when a column is hidden or "unhidden".
6604 * @param {ColumnModel} this
6605 * @param {Number} columnIndex The column index
6606 * @param {Boolean} hidden true if hidden, false otherwise
6608 "hiddenchange": true,
6610 * @event columnmoved
6611 * Fires when a column is moved.
6612 * @param {ColumnModel} this
6613 * @param {Number} oldIndex
6614 * @param {Number} newIndex
6616 "columnmoved" : true,
6618 * @event columlockchange
6619 * Fires when a column's locked state is changed
6620 * @param {ColumnModel} this
6621 * @param {Number} colIndex
6622 * @param {Boolean} locked true if locked
6624 "columnlockchange" : true
6626 Roo.grid.ColumnModel.superclass.constructor.call(this);
6628 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
6630 * @cfg {String} header The header text to display in the Grid view.
6633 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
6634 * {@link Roo.data.Record} definition from which to draw the column's value. If not
6635 * specified, the column's index is used as an index into the Record's data Array.
6638 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
6639 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
6642 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
6643 * Defaults to the value of the {@link #defaultSortable} property.
6644 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
6647 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
6650 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
6653 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
6656 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
6659 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
6660 * given the cell's data value. See {@link #setRenderer}. If not specified, the
6661 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
6662 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
6665 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
6668 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
6671 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
6674 * @cfg {String} cursor (Optional)
6677 * @cfg {String} tooltip (Optional)
6680 * @cfg {Number} xs (Optional)
6683 * @cfg {Number} sm (Optional)
6686 * @cfg {Number} md (Optional)
6689 * @cfg {Number} lg (Optional)
6692 * Returns the id of the column at the specified index.
6693 * @param {Number} index The column index
6694 * @return {String} the id
6696 getColumnId : function(index){
6697 return this.config[index].id;
6701 * Returns the column for a specified id.
6702 * @param {String} id The column id
6703 * @return {Object} the column
6705 getColumnById : function(id){
6706 return this.lookup[id];
6711 * Returns the column for a specified dataIndex.
6712 * @param {String} dataIndex The column dataIndex
6713 * @return {Object|Boolean} the column or false if not found
6715 getColumnByDataIndex: function(dataIndex){
6716 var index = this.findColumnIndex(dataIndex);
6717 return index > -1 ? this.config[index] : false;
6721 * Returns the index for a specified column id.
6722 * @param {String} id The column id
6723 * @return {Number} the index, or -1 if not found
6725 getIndexById : function(id){
6726 for(var i = 0, len = this.config.length; i < len; i++){
6727 if(this.config[i].id == id){
6735 * Returns the index for a specified column dataIndex.
6736 * @param {String} dataIndex The column dataIndex
6737 * @return {Number} the index, or -1 if not found
6740 findColumnIndex : function(dataIndex){
6741 for(var i = 0, len = this.config.length; i < len; i++){
6742 if(this.config[i].dataIndex == dataIndex){
6750 moveColumn : function(oldIndex, newIndex){
6751 var c = this.config[oldIndex];
6752 this.config.splice(oldIndex, 1);
6753 this.config.splice(newIndex, 0, c);
6754 this.dataMap = null;
6755 this.fireEvent("columnmoved", this, oldIndex, newIndex);
6758 isLocked : function(colIndex){
6759 return this.config[colIndex].locked === true;
6762 setLocked : function(colIndex, value, suppressEvent){
6763 if(this.isLocked(colIndex) == value){
6766 this.config[colIndex].locked = value;
6768 this.fireEvent("columnlockchange", this, colIndex, value);
6772 getTotalLockedWidth : function(){
6774 for(var i = 0; i < this.config.length; i++){
6775 if(this.isLocked(i) && !this.isHidden(i)){
6776 this.totalWidth += this.getColumnWidth(i);
6782 getLockedCount : function(){
6783 for(var i = 0, len = this.config.length; i < len; i++){
6784 if(!this.isLocked(i)){
6789 return this.config.length;
6793 * Returns the number of columns.
6796 getColumnCount : function(visibleOnly){
6797 if(visibleOnly === true){
6799 for(var i = 0, len = this.config.length; i < len; i++){
6800 if(!this.isHidden(i)){
6806 return this.config.length;
6810 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
6811 * @param {Function} fn
6812 * @param {Object} scope (optional)
6813 * @return {Array} result
6815 getColumnsBy : function(fn, scope){
6817 for(var i = 0, len = this.config.length; i < len; i++){
6818 var c = this.config[i];
6819 if(fn.call(scope||this, c, i) === true){
6827 * Returns true if the specified column is sortable.
6828 * @param {Number} col The column index
6831 isSortable : function(col){
6832 if(typeof this.config[col].sortable == "undefined"){
6833 return this.defaultSortable;
6835 return this.config[col].sortable;
6839 * Returns the rendering (formatting) function defined for the column.
6840 * @param {Number} col The column index.
6841 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
6843 getRenderer : function(col){
6844 if(!this.config[col].renderer){
6845 return Roo.grid.ColumnModel.defaultRenderer;
6847 return this.config[col].renderer;
6851 * Sets the rendering (formatting) function for a column.
6852 * @param {Number} col The column index
6853 * @param {Function} fn The function to use to process the cell's raw data
6854 * to return HTML markup for the grid view. The render function is called with
6855 * the following parameters:<ul>
6856 * <li>Data value.</li>
6857 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
6858 * <li>css A CSS style string to apply to the table cell.</li>
6859 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
6860 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
6861 * <li>Row index</li>
6862 * <li>Column index</li>
6863 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
6865 setRenderer : function(col, fn){
6866 this.config[col].renderer = fn;
6870 * Returns the width for the specified column.
6871 * @param {Number} col The column index
6874 getColumnWidth : function(col){
6875 return this.config[col].width * 1 || this.defaultWidth;
6879 * Sets the width for a column.
6880 * @param {Number} col The column index
6881 * @param {Number} width The new width
6883 setColumnWidth : function(col, width, suppressEvent){
6884 this.config[col].width = width;
6885 this.totalWidth = null;
6887 this.fireEvent("widthchange", this, col, width);
6892 * Returns the total width of all columns.
6893 * @param {Boolean} includeHidden True to include hidden column widths
6896 getTotalWidth : function(includeHidden){
6897 if(!this.totalWidth){
6898 this.totalWidth = 0;
6899 for(var i = 0, len = this.config.length; i < len; i++){
6900 if(includeHidden || !this.isHidden(i)){
6901 this.totalWidth += this.getColumnWidth(i);
6905 return this.totalWidth;
6909 * Returns the header for the specified column.
6910 * @param {Number} col The column index
6913 getColumnHeader : function(col){
6914 return this.config[col].header;
6918 * Sets the header for a column.
6919 * @param {Number} col The column index
6920 * @param {String} header The new header
6922 setColumnHeader : function(col, header){
6923 this.config[col].header = header;
6924 this.fireEvent("headerchange", this, col, header);
6928 * Returns the tooltip for the specified column.
6929 * @param {Number} col The column index
6932 getColumnTooltip : function(col){
6933 return this.config[col].tooltip;
6936 * Sets the tooltip for a column.
6937 * @param {Number} col The column index
6938 * @param {String} tooltip The new tooltip
6940 setColumnTooltip : function(col, tooltip){
6941 this.config[col].tooltip = tooltip;
6945 * Returns the dataIndex for the specified column.
6946 * @param {Number} col The column index
6949 getDataIndex : function(col){
6950 return this.config[col].dataIndex;
6954 * Sets the dataIndex for a column.
6955 * @param {Number} col The column index
6956 * @param {Number} dataIndex The new dataIndex
6958 setDataIndex : function(col, dataIndex){
6959 this.config[col].dataIndex = dataIndex;
6965 * Returns true if the cell is editable.
6966 * @param {Number} colIndex The column index
6967 * @param {Number} rowIndex The row index - this is nto actually used..?
6970 isCellEditable : function(colIndex, rowIndex){
6971 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6975 * Returns the editor defined for the cell/column.
6976 * return false or null to disable editing.
6977 * @param {Number} colIndex The column index
6978 * @param {Number} rowIndex The row index
6981 getCellEditor : function(colIndex, rowIndex){
6982 return this.config[colIndex].editor;
6986 * Sets if a column is editable.
6987 * @param {Number} col The column index
6988 * @param {Boolean} editable True if the column is editable
6990 setEditable : function(col, editable){
6991 this.config[col].editable = editable;
6996 * Returns true if the column is hidden.
6997 * @param {Number} colIndex The column index
7000 isHidden : function(colIndex){
7001 return this.config[colIndex].hidden;
7006 * Returns true if the column width cannot be changed
7008 isFixed : function(colIndex){
7009 return this.config[colIndex].fixed;
7013 * Returns true if the column can be resized
7016 isResizable : function(colIndex){
7017 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
7020 * Sets if a column is hidden.
7021 * @param {Number} colIndex The column index
7022 * @param {Boolean} hidden True if the column is hidden
7024 setHidden : function(colIndex, hidden){
7025 this.config[colIndex].hidden = hidden;
7026 this.totalWidth = null;
7027 this.fireEvent("hiddenchange", this, colIndex, hidden);
7031 * Sets the editor for a column.
7032 * @param {Number} col The column index
7033 * @param {Object} editor The editor object
7035 setEditor : function(col, editor){
7036 this.config[col].editor = editor;
7040 Roo.grid.ColumnModel.defaultRenderer = function(value)
7042 if(typeof value == "object") {
7045 if(typeof value == "string" && value.length < 1){
7049 return String.format("{0}", value);
7052 // Alias for backwards compatibility
7053 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
7056 * Ext JS Library 1.1.1
7057 * Copyright(c) 2006-2007, Ext JS, LLC.
7059 * Originally Released Under LGPL - original licence link has changed is not relivant.
7062 * <script type="text/javascript">
7066 * @class Roo.LoadMask
7067 * A simple utility class for generically masking elements while loading data. If the element being masked has
7068 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
7069 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
7070 * element's UpdateManager load indicator and will be destroyed after the initial load.
7072 * Create a new LoadMask
7073 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
7074 * @param {Object} config The config object
7076 Roo.LoadMask = function(el, config){
7077 this.el = Roo.get(el);
7078 Roo.apply(this, config);
7080 this.store.on('beforeload', this.onBeforeLoad, this);
7081 this.store.on('load', this.onLoad, this);
7082 this.store.on('loadexception', this.onLoadException, this);
7083 this.removeMask = false;
7085 var um = this.el.getUpdateManager();
7086 um.showLoadIndicator = false; // disable the default indicator
7087 um.on('beforeupdate', this.onBeforeLoad, this);
7088 um.on('update', this.onLoad, this);
7089 um.on('failure', this.onLoad, this);
7090 this.removeMask = true;
7094 Roo.LoadMask.prototype = {
7096 * @cfg {Boolean} removeMask
7097 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
7098 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
7102 * The text to display in a centered loading message box (defaults to 'Loading...')
7106 * @cfg {String} msgCls
7107 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
7109 msgCls : 'x-mask-loading',
7112 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
7118 * Disables the mask to prevent it from being displayed
7120 disable : function(){
7121 this.disabled = true;
7125 * Enables the mask so that it can be displayed
7127 enable : function(){
7128 this.disabled = false;
7131 onLoadException : function()
7135 if (typeof(arguments[3]) != 'undefined') {
7136 Roo.MessageBox.alert("Error loading",arguments[3]);
7140 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7141 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7148 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7153 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7157 onBeforeLoad : function(){
7159 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
7164 destroy : function(){
7166 this.store.un('beforeload', this.onBeforeLoad, this);
7167 this.store.un('load', this.onLoad, this);
7168 this.store.un('loadexception', this.onLoadException, this);
7170 var um = this.el.getUpdateManager();
7171 um.un('beforeupdate', this.onBeforeLoad, this);
7172 um.un('update', this.onLoad, this);
7173 um.un('failure', this.onLoad, this);
7184 * @class Roo.bootstrap.Table
7185 * @extends Roo.bootstrap.Component
7186 * Bootstrap Table class
7187 * @cfg {String} cls table class
7188 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
7189 * @cfg {String} bgcolor Specifies the background color for a table
7190 * @cfg {Number} border Specifies whether the table cells should have borders or not
7191 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
7192 * @cfg {Number} cellspacing Specifies the space between cells
7193 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
7194 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
7195 * @cfg {String} sortable Specifies that the table should be sortable
7196 * @cfg {String} summary Specifies a summary of the content of a table
7197 * @cfg {Number} width Specifies the width of a table
7198 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
7200 * @cfg {boolean} striped Should the rows be alternative striped
7201 * @cfg {boolean} bordered Add borders to the table
7202 * @cfg {boolean} hover Add hover highlighting
7203 * @cfg {boolean} condensed Format condensed
7204 * @cfg {boolean} responsive Format condensed
7205 * @cfg {Boolean} loadMask (true|false) default false
7206 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
7207 * @cfg {Boolean} headerShow (true|false) generate thead, default true
7208 * @cfg {Boolean} rowSelection (true|false) default false
7209 * @cfg {Boolean} cellSelection (true|false) default false
7210 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
7211 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
7212 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
7213 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
7217 * Create a new Table
7218 * @param {Object} config The config object
7221 Roo.bootstrap.Table = function(config){
7222 Roo.bootstrap.Table.superclass.constructor.call(this, config);
7227 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
7228 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
7229 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
7230 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
7232 this.sm = this.sm || {xtype: 'RowSelectionModel'};
7234 this.sm.grid = this;
7235 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
7236 this.sm = this.selModel;
7237 this.sm.xmodule = this.xmodule || false;
7240 if (this.cm && typeof(this.cm.config) == 'undefined') {
7241 this.colModel = new Roo.grid.ColumnModel(this.cm);
7242 this.cm = this.colModel;
7243 this.cm.xmodule = this.xmodule || false;
7246 this.store= Roo.factory(this.store, Roo.data);
7247 this.ds = this.store;
7248 this.ds.xmodule = this.xmodule || false;
7251 if (this.footer && this.store) {
7252 this.footer.dataSource = this.ds;
7253 this.footer = Roo.factory(this.footer);
7260 * Fires when a cell is clicked
7261 * @param {Roo.bootstrap.Table} this
7262 * @param {Roo.Element} el
7263 * @param {Number} rowIndex
7264 * @param {Number} columnIndex
7265 * @param {Roo.EventObject} e
7269 * @event celldblclick
7270 * Fires when a cell is double clicked
7271 * @param {Roo.bootstrap.Table} this
7272 * @param {Roo.Element} el
7273 * @param {Number} rowIndex
7274 * @param {Number} columnIndex
7275 * @param {Roo.EventObject} e
7277 "celldblclick" : true,
7280 * Fires when a row is clicked
7281 * @param {Roo.bootstrap.Table} this
7282 * @param {Roo.Element} el
7283 * @param {Number} rowIndex
7284 * @param {Roo.EventObject} e
7288 * @event rowdblclick
7289 * Fires when a row is double clicked
7290 * @param {Roo.bootstrap.Table} this
7291 * @param {Roo.Element} el
7292 * @param {Number} rowIndex
7293 * @param {Roo.EventObject} e
7295 "rowdblclick" : true,
7298 * Fires when a mouseover occur
7299 * @param {Roo.bootstrap.Table} this
7300 * @param {Roo.Element} el
7301 * @param {Number} rowIndex
7302 * @param {Number} columnIndex
7303 * @param {Roo.EventObject} e
7308 * Fires when a mouseout occur
7309 * @param {Roo.bootstrap.Table} this
7310 * @param {Roo.Element} el
7311 * @param {Number} rowIndex
7312 * @param {Number} columnIndex
7313 * @param {Roo.EventObject} e
7318 * Fires when a row is rendered, so you can change add a style to it.
7319 * @param {Roo.bootstrap.Table} this
7320 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
7324 * @event rowsrendered
7325 * Fires when all the rows have been rendered
7326 * @param {Roo.bootstrap.Table} this
7328 'rowsrendered' : true,
7330 * @event contextmenu
7331 * The raw contextmenu event for the entire grid.
7332 * @param {Roo.EventObject} e
7334 "contextmenu" : true,
7336 * @event rowcontextmenu
7337 * Fires when a row is right clicked
7338 * @param {Roo.bootstrap.Table} this
7339 * @param {Number} rowIndex
7340 * @param {Roo.EventObject} e
7342 "rowcontextmenu" : true,
7344 * @event cellcontextmenu
7345 * Fires when a cell is right clicked
7346 * @param {Roo.bootstrap.Table} this
7347 * @param {Number} rowIndex
7348 * @param {Number} cellIndex
7349 * @param {Roo.EventObject} e
7351 "cellcontextmenu" : true,
7353 * @event headercontextmenu
7354 * Fires when a header is right clicked
7355 * @param {Roo.bootstrap.Table} this
7356 * @param {Number} columnIndex
7357 * @param {Roo.EventObject} e
7359 "headercontextmenu" : true
7363 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
7389 rowSelection : false,
7390 cellSelection : false,
7393 // Roo.Element - the tbody
7395 // Roo.Element - thead element
7398 container: false, // used by gridpanel...
7404 auto_hide_footer : false,
7406 getAutoCreate : function()
7408 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
7415 if (this.scrollBody) {
7416 cfg.cls += ' table-body-fixed';
7419 cfg.cls += ' table-striped';
7423 cfg.cls += ' table-hover';
7425 if (this.bordered) {
7426 cfg.cls += ' table-bordered';
7428 if (this.condensed) {
7429 cfg.cls += ' table-condensed';
7431 if (this.responsive) {
7432 cfg.cls += ' table-responsive';
7436 cfg.cls+= ' ' +this.cls;
7439 // this lot should be simplifed...
7452 ].forEach(function(k) {
7460 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
7463 if(this.store || this.cm){
7464 if(this.headerShow){
7465 cfg.cn.push(this.renderHeader());
7468 cfg.cn.push(this.renderBody());
7470 if(this.footerShow){
7471 cfg.cn.push(this.renderFooter());
7473 // where does this come from?
7474 //cfg.cls+= ' TableGrid';
7477 return { cn : [ cfg ] };
7480 initEvents : function()
7482 if(!this.store || !this.cm){
7485 if (this.selModel) {
7486 this.selModel.initEvents();
7490 //Roo.log('initEvents with ds!!!!');
7492 this.mainBody = this.el.select('tbody', true).first();
7493 this.mainHead = this.el.select('thead', true).first();
7494 this.mainFoot = this.el.select('tfoot', true).first();
7500 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7501 e.on('click', _this.sort, _this);
7504 this.mainBody.on("click", this.onClick, this);
7505 this.mainBody.on("dblclick", this.onDblClick, this);
7507 // why is this done????? = it breaks dialogs??
7508 //this.parent().el.setStyle('position', 'relative');
7512 this.footer.parentId = this.id;
7513 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
7516 this.el.select('tfoot tr td').first().addClass('hide');
7521 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
7524 this.store.on('load', this.onLoad, this);
7525 this.store.on('beforeload', this.onBeforeLoad, this);
7526 this.store.on('update', this.onUpdate, this);
7527 this.store.on('add', this.onAdd, this);
7528 this.store.on("clear", this.clear, this);
7530 this.el.on("contextmenu", this.onContextMenu, this);
7532 this.mainBody.on('scroll', this.onBodyScroll, this);
7534 this.cm.on("headerchange", this.onHeaderChange, this);
7536 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
7540 onContextMenu : function(e, t)
7542 this.processEvent("contextmenu", e);
7545 processEvent : function(name, e)
7547 if (name != 'touchstart' ) {
7548 this.fireEvent(name, e);
7551 var t = e.getTarget();
7553 var cell = Roo.get(t);
7559 if(cell.findParent('tfoot', false, true)){
7563 if(cell.findParent('thead', false, true)){
7565 if(e.getTarget().nodeName.toLowerCase() != 'th'){
7566 cell = Roo.get(t).findParent('th', false, true);
7568 Roo.log("failed to find th in thead?");
7569 Roo.log(e.getTarget());
7574 var cellIndex = cell.dom.cellIndex;
7576 var ename = name == 'touchstart' ? 'click' : name;
7577 this.fireEvent("header" + ename, this, cellIndex, e);
7582 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7583 cell = Roo.get(t).findParent('td', false, true);
7585 Roo.log("failed to find th in tbody?");
7586 Roo.log(e.getTarget());
7591 var row = cell.findParent('tr', false, true);
7592 var cellIndex = cell.dom.cellIndex;
7593 var rowIndex = row.dom.rowIndex - 1;
7597 this.fireEvent("row" + name, this, rowIndex, e);
7601 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
7607 onMouseover : function(e, el)
7609 var cell = Roo.get(el);
7615 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7616 cell = cell.findParent('td', false, true);
7619 var row = cell.findParent('tr', false, true);
7620 var cellIndex = cell.dom.cellIndex;
7621 var rowIndex = row.dom.rowIndex - 1; // start from 0
7623 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
7627 onMouseout : function(e, el)
7629 var cell = Roo.get(el);
7635 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7636 cell = cell.findParent('td', false, true);
7639 var row = cell.findParent('tr', false, true);
7640 var cellIndex = cell.dom.cellIndex;
7641 var rowIndex = row.dom.rowIndex - 1; // start from 0
7643 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
7647 onClick : function(e, el)
7649 var cell = Roo.get(el);
7651 if(!cell || (!this.cellSelection && !this.rowSelection)){
7655 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7656 cell = cell.findParent('td', false, true);
7659 if(!cell || typeof(cell) == 'undefined'){
7663 var row = cell.findParent('tr', false, true);
7665 if(!row || typeof(row) == 'undefined'){
7669 var cellIndex = cell.dom.cellIndex;
7670 var rowIndex = this.getRowIndex(row);
7672 // why??? - should these not be based on SelectionModel?
7673 if(this.cellSelection){
7674 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
7677 if(this.rowSelection){
7678 this.fireEvent('rowclick', this, row, rowIndex, e);
7684 onDblClick : function(e,el)
7686 var cell = Roo.get(el);
7688 if(!cell || (!this.cellSelection && !this.rowSelection)){
7692 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7693 cell = cell.findParent('td', false, true);
7696 if(!cell || typeof(cell) == 'undefined'){
7700 var row = cell.findParent('tr', false, true);
7702 if(!row || typeof(row) == 'undefined'){
7706 var cellIndex = cell.dom.cellIndex;
7707 var rowIndex = this.getRowIndex(row);
7709 if(this.cellSelection){
7710 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
7713 if(this.rowSelection){
7714 this.fireEvent('rowdblclick', this, row, rowIndex, e);
7718 sort : function(e,el)
7720 var col = Roo.get(el);
7722 if(!col.hasClass('sortable')){
7726 var sort = col.attr('sort');
7729 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
7733 this.store.sortInfo = {field : sort, direction : dir};
7736 Roo.log("calling footer first");
7737 this.footer.onClick('first');
7740 this.store.load({ params : { start : 0 } });
7744 renderHeader : function()
7752 this.totalWidth = 0;
7754 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7756 var config = cm.config[i];
7760 cls : 'x-hcol-' + i,
7762 html: cm.getColumnHeader(i)
7767 if(typeof(config.sortable) != 'undefined' && config.sortable){
7769 c.html = '<i class="glyphicon"></i>' + c.html;
7772 // could use BS4 hidden-..-down
7774 if(typeof(config.lgHeader) != 'undefined'){
7775 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
7778 if(typeof(config.mdHeader) != 'undefined'){
7779 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
7782 if(typeof(config.smHeader) != 'undefined'){
7783 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
7786 if(typeof(config.xsHeader) != 'undefined'){
7787 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
7794 if(typeof(config.tooltip) != 'undefined'){
7795 c.tooltip = config.tooltip;
7798 if(typeof(config.colspan) != 'undefined'){
7799 c.colspan = config.colspan;
7802 if(typeof(config.hidden) != 'undefined' && config.hidden){
7803 c.style += ' display:none;';
7806 if(typeof(config.dataIndex) != 'undefined'){
7807 c.sort = config.dataIndex;
7812 if(typeof(config.align) != 'undefined' && config.align.length){
7813 c.style += ' text-align:' + config.align + ';';
7816 if(typeof(config.width) != 'undefined'){
7817 c.style += ' width:' + config.width + 'px;';
7818 this.totalWidth += config.width;
7820 this.totalWidth += 100; // assume minimum of 100 per column?
7823 if(typeof(config.cls) != 'undefined'){
7824 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
7827 ['xs','sm','md','lg'].map(function(size){
7829 if(typeof(config[size]) == 'undefined'){
7833 if (!config[size]) { // 0 = hidden
7834 // BS 4 '0' is treated as hide that column and below.
7835 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
7839 c.cls += ' col-' + size + '-' + config[size] + (
7840 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7852 renderBody : function()
7862 colspan : this.cm.getColumnCount()
7872 renderFooter : function()
7882 colspan : this.cm.getColumnCount()
7896 // Roo.log('ds onload');
7901 var ds = this.store;
7903 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7904 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
7905 if (_this.store.sortInfo) {
7907 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
7908 e.select('i', true).addClass(['glyphicon-arrow-up']);
7911 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
7912 e.select('i', true).addClass(['glyphicon-arrow-down']);
7917 var tbody = this.mainBody;
7919 if(ds.getCount() > 0){
7920 ds.data.each(function(d,rowIndex){
7921 var row = this.renderRow(cm, ds, rowIndex);
7923 tbody.createChild(row);
7927 if(row.cellObjects.length){
7928 Roo.each(row.cellObjects, function(r){
7929 _this.renderCellObject(r);
7936 var tfoot = this.el.select('tfoot', true).first();
7938 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7940 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7942 var total = this.ds.getTotalCount();
7944 if(this.footer.pageSize < total){
7945 this.mainFoot.show();
7949 Roo.each(this.el.select('tbody td', true).elements, function(e){
7950 e.on('mouseover', _this.onMouseover, _this);
7953 Roo.each(this.el.select('tbody td', true).elements, function(e){
7954 e.on('mouseout', _this.onMouseout, _this);
7956 this.fireEvent('rowsrendered', this);
7962 onUpdate : function(ds,record)
7964 this.refreshRow(record);
7968 onRemove : function(ds, record, index, isUpdate){
7969 if(isUpdate !== true){
7970 this.fireEvent("beforerowremoved", this, index, record);
7972 var bt = this.mainBody.dom;
7974 var rows = this.el.select('tbody > tr', true).elements;
7976 if(typeof(rows[index]) != 'undefined'){
7977 bt.removeChild(rows[index].dom);
7980 // if(bt.rows[index]){
7981 // bt.removeChild(bt.rows[index]);
7984 if(isUpdate !== true){
7985 //this.stripeRows(index);
7986 //this.syncRowHeights(index, index);
7988 this.fireEvent("rowremoved", this, index, record);
7992 onAdd : function(ds, records, rowIndex)
7994 //Roo.log('on Add called');
7995 // - note this does not handle multiple adding very well..
7996 var bt = this.mainBody.dom;
7997 for (var i =0 ; i < records.length;i++) {
7998 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7999 //Roo.log(records[i]);
8000 //Roo.log(this.store.getAt(rowIndex+i));
8001 this.insertRow(this.store, rowIndex + i, false);
8008 refreshRow : function(record){
8009 var ds = this.store, index;
8010 if(typeof record == 'number'){
8012 record = ds.getAt(index);
8014 index = ds.indexOf(record);
8016 this.insertRow(ds, index, true);
8018 this.onRemove(ds, record, index+1, true);
8020 //this.syncRowHeights(index, index);
8022 this.fireEvent("rowupdated", this, index, record);
8025 insertRow : function(dm, rowIndex, isUpdate){
8028 this.fireEvent("beforerowsinserted", this, rowIndex);
8030 //var s = this.getScrollState();
8031 var row = this.renderRow(this.cm, this.store, rowIndex);
8032 // insert before rowIndex..
8033 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
8037 if(row.cellObjects.length){
8038 Roo.each(row.cellObjects, function(r){
8039 _this.renderCellObject(r);
8044 this.fireEvent("rowsinserted", this, rowIndex);
8045 //this.syncRowHeights(firstRow, lastRow);
8046 //this.stripeRows(firstRow);
8053 getRowDom : function(rowIndex)
8055 var rows = this.el.select('tbody > tr', true).elements;
8057 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
8060 // returns the object tree for a tr..
8063 renderRow : function(cm, ds, rowIndex)
8065 var d = ds.getAt(rowIndex);
8069 cls : 'x-row-' + rowIndex,
8073 var cellObjects = [];
8075 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8076 var config = cm.config[i];
8078 var renderer = cm.getRenderer(i);
8082 if(typeof(renderer) !== 'undefined'){
8083 value = renderer(d.data[cm.getDataIndex(i)], false, d);
8085 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
8086 // and are rendered into the cells after the row is rendered - using the id for the element.
8088 if(typeof(value) === 'object'){
8098 rowIndex : rowIndex,
8103 this.fireEvent('rowclass', this, rowcfg);
8107 cls : rowcfg.rowClass + ' x-col-' + i,
8109 html: (typeof(value) === 'object') ? '' : value
8116 if(typeof(config.colspan) != 'undefined'){
8117 td.colspan = config.colspan;
8120 if(typeof(config.hidden) != 'undefined' && config.hidden){
8121 td.style += ' display:none;';
8124 if(typeof(config.align) != 'undefined' && config.align.length){
8125 td.style += ' text-align:' + config.align + ';';
8127 if(typeof(config.valign) != 'undefined' && config.valign.length){
8128 td.style += ' vertical-align:' + config.valign + ';';
8131 if(typeof(config.width) != 'undefined'){
8132 td.style += ' width:' + config.width + 'px;';
8135 if(typeof(config.cursor) != 'undefined'){
8136 td.style += ' cursor:' + config.cursor + ';';
8139 if(typeof(config.cls) != 'undefined'){
8140 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
8143 ['xs','sm','md','lg'].map(function(size){
8145 if(typeof(config[size]) == 'undefined'){
8151 if (!config[size]) { // 0 = hidden
8152 // BS 4 '0' is treated as hide that column and below.
8153 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
8157 td.cls += ' col-' + size + '-' + config[size] + (
8158 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8168 row.cellObjects = cellObjects;
8176 onBeforeLoad : function()
8185 this.el.select('tbody', true).first().dom.innerHTML = '';
8188 * Show or hide a row.
8189 * @param {Number} rowIndex to show or hide
8190 * @param {Boolean} state hide
8192 setRowVisibility : function(rowIndex, state)
8194 var bt = this.mainBody.dom;
8196 var rows = this.el.select('tbody > tr', true).elements;
8198 if(typeof(rows[rowIndex]) == 'undefined'){
8201 rows[rowIndex].dom.style.display = state ? '' : 'none';
8205 getSelectionModel : function(){
8207 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
8209 return this.selModel;
8212 * Render the Roo.bootstrap object from renderder
8214 renderCellObject : function(r)
8218 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
8220 var t = r.cfg.render(r.container);
8223 Roo.each(r.cfg.cn, function(c){
8225 container: t.getChildContainer(),
8228 _this.renderCellObject(child);
8233 getRowIndex : function(row)
8237 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
8248 * Returns the grid's underlying element = used by panel.Grid
8249 * @return {Element} The element
8251 getGridEl : function(){
8255 * Forces a resize - used by panel.Grid
8256 * @return {Element} The element
8258 autoSize : function()
8260 //var ctr = Roo.get(this.container.dom.parentElement);
8261 var ctr = Roo.get(this.el.dom);
8263 var thd = this.getGridEl().select('thead',true).first();
8264 var tbd = this.getGridEl().select('tbody', true).first();
8265 var tfd = this.getGridEl().select('tfoot', true).first();
8267 var cw = ctr.getWidth();
8271 tbd.setWidth(ctr.getWidth());
8272 // if the body has a max height - and then scrolls - we should perhaps set up the height here
8273 // this needs fixing for various usage - currently only hydra job advers I think..
8275 // ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
8277 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
8280 cw = Math.max(cw, this.totalWidth);
8281 this.getGridEl().select('tr',true).setWidth(cw);
8282 // resize 'expandable coloumn?
8284 return; // we doe not have a view in this design..
8287 onBodyScroll: function()
8289 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
8291 this.mainHead.setStyle({
8292 'position' : 'relative',
8293 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
8299 var scrollHeight = this.mainBody.dom.scrollHeight;
8301 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
8303 var height = this.mainBody.getHeight();
8305 if(scrollHeight - height == scrollTop) {
8307 var total = this.ds.getTotalCount();
8309 if(this.footer.cursor + this.footer.pageSize < total){
8311 this.footer.ds.load({
8313 start : this.footer.cursor + this.footer.pageSize,
8314 limit : this.footer.pageSize
8324 onHeaderChange : function()
8326 var header = this.renderHeader();
8327 var table = this.el.select('table', true).first();
8329 this.mainHead.remove();
8330 this.mainHead = table.createChild(header, this.mainBody, false);
8333 onHiddenChange : function(colModel, colIndex, hidden)
8335 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
8336 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
8338 this.CSS.updateRule(thSelector, "display", "");
8339 this.CSS.updateRule(tdSelector, "display", "");
8342 this.CSS.updateRule(thSelector, "display", "none");
8343 this.CSS.updateRule(tdSelector, "display", "none");
8346 this.onHeaderChange();
8350 setColumnWidth: function(col_index, width)
8352 // width = "md-2 xs-2..."
8353 if(!this.colModel.config[col_index]) {
8357 var w = width.split(" ");
8359 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
8361 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
8364 for(var j = 0; j < w.length; j++) {
8370 var size_cls = w[j].split("-");
8372 if(!Number.isInteger(size_cls[1] * 1)) {
8376 if(!this.colModel.config[col_index][size_cls[0]]) {
8380 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8384 h_row[0].classList.replace(
8385 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8386 "col-"+size_cls[0]+"-"+size_cls[1]
8389 for(var i = 0; i < rows.length; i++) {
8391 var size_cls = w[j].split("-");
8393 if(!Number.isInteger(size_cls[1] * 1)) {
8397 if(!this.colModel.config[col_index][size_cls[0]]) {
8401 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8405 rows[i].classList.replace(
8406 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8407 "col-"+size_cls[0]+"-"+size_cls[1]
8411 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
8426 * @class Roo.bootstrap.TableCell
8427 * @extends Roo.bootstrap.Component
8428 * Bootstrap TableCell class
8429 * @cfg {String} html cell contain text
8430 * @cfg {String} cls cell class
8431 * @cfg {String} tag cell tag (td|th) default td
8432 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
8433 * @cfg {String} align Aligns the content in a cell
8434 * @cfg {String} axis Categorizes cells
8435 * @cfg {String} bgcolor Specifies the background color of a cell
8436 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8437 * @cfg {Number} colspan Specifies the number of columns a cell should span
8438 * @cfg {String} headers Specifies one or more header cells a cell is related to
8439 * @cfg {Number} height Sets the height of a cell
8440 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
8441 * @cfg {Number} rowspan Sets the number of rows a cell should span
8442 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
8443 * @cfg {String} valign Vertical aligns the content in a cell
8444 * @cfg {Number} width Specifies the width of a cell
8447 * Create a new TableCell
8448 * @param {Object} config The config object
8451 Roo.bootstrap.TableCell = function(config){
8452 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
8455 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
8475 getAutoCreate : function(){
8476 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
8496 cfg.align=this.align
8502 cfg.bgcolor=this.bgcolor
8505 cfg.charoff=this.charoff
8508 cfg.colspan=this.colspan
8511 cfg.headers=this.headers
8514 cfg.height=this.height
8517 cfg.nowrap=this.nowrap
8520 cfg.rowspan=this.rowspan
8523 cfg.scope=this.scope
8526 cfg.valign=this.valign
8529 cfg.width=this.width
8548 * @class Roo.bootstrap.TableRow
8549 * @extends Roo.bootstrap.Component
8550 * Bootstrap TableRow class
8551 * @cfg {String} cls row class
8552 * @cfg {String} align Aligns the content in a table row
8553 * @cfg {String} bgcolor Specifies a background color for a table row
8554 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8555 * @cfg {String} valign Vertical aligns the content in a table row
8558 * Create a new TableRow
8559 * @param {Object} config The config object
8562 Roo.bootstrap.TableRow = function(config){
8563 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
8566 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
8574 getAutoCreate : function(){
8575 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
8585 cfg.align = this.align;
8588 cfg.bgcolor = this.bgcolor;
8591 cfg.charoff = this.charoff;
8594 cfg.valign = this.valign;
8612 * @class Roo.bootstrap.TableBody
8613 * @extends Roo.bootstrap.Component
8614 * Bootstrap TableBody class
8615 * @cfg {String} cls element class
8616 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
8617 * @cfg {String} align Aligns the content inside the element
8618 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
8619 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
8622 * Create a new TableBody
8623 * @param {Object} config The config object
8626 Roo.bootstrap.TableBody = function(config){
8627 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
8630 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
8638 getAutoCreate : function(){
8639 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
8653 cfg.align = this.align;
8656 cfg.charoff = this.charoff;
8659 cfg.valign = this.valign;
8666 // initEvents : function()
8673 // this.store = Roo.factory(this.store, Roo.data);
8674 // this.store.on('load', this.onLoad, this);
8676 // this.store.load();
8680 // onLoad: function ()
8682 // this.fireEvent('load', this);
8692 * Ext JS Library 1.1.1
8693 * Copyright(c) 2006-2007, Ext JS, LLC.
8695 * Originally Released Under LGPL - original licence link has changed is not relivant.
8698 * <script type="text/javascript">
8701 // as we use this in bootstrap.
8702 Roo.namespace('Roo.form');
8704 * @class Roo.form.Action
8705 * Internal Class used to handle form actions
8707 * @param {Roo.form.BasicForm} el The form element or its id
8708 * @param {Object} config Configuration options
8713 // define the action interface
8714 Roo.form.Action = function(form, options){
8716 this.options = options || {};
8719 * Client Validation Failed
8722 Roo.form.Action.CLIENT_INVALID = 'client';
8724 * Server Validation Failed
8727 Roo.form.Action.SERVER_INVALID = 'server';
8729 * Connect to Server Failed
8732 Roo.form.Action.CONNECT_FAILURE = 'connect';
8734 * Reading Data from Server Failed
8737 Roo.form.Action.LOAD_FAILURE = 'load';
8739 Roo.form.Action.prototype = {
8741 failureType : undefined,
8742 response : undefined,
8746 run : function(options){
8751 success : function(response){
8756 handleResponse : function(response){
8760 // default connection failure
8761 failure : function(response){
8763 this.response = response;
8764 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8765 this.form.afterAction(this, false);
8768 processResponse : function(response){
8769 this.response = response;
8770 if(!response.responseText){
8773 this.result = this.handleResponse(response);
8777 // utility functions used internally
8778 getUrl : function(appendParams){
8779 var url = this.options.url || this.form.url || this.form.el.dom.action;
8781 var p = this.getParams();
8783 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
8789 getMethod : function(){
8790 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
8793 getParams : function(){
8794 var bp = this.form.baseParams;
8795 var p = this.options.params;
8797 if(typeof p == "object"){
8798 p = Roo.urlEncode(Roo.applyIf(p, bp));
8799 }else if(typeof p == 'string' && bp){
8800 p += '&' + Roo.urlEncode(bp);
8803 p = Roo.urlEncode(bp);
8808 createCallback : function(){
8810 success: this.success,
8811 failure: this.failure,
8813 timeout: (this.form.timeout*1000),
8814 upload: this.form.fileUpload ? this.success : undefined
8819 Roo.form.Action.Submit = function(form, options){
8820 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
8823 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
8826 haveProgress : false,
8827 uploadComplete : false,
8829 // uploadProgress indicator.
8830 uploadProgress : function()
8832 if (!this.form.progressUrl) {
8836 if (!this.haveProgress) {
8837 Roo.MessageBox.progress("Uploading", "Uploading");
8839 if (this.uploadComplete) {
8840 Roo.MessageBox.hide();
8844 this.haveProgress = true;
8846 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
8848 var c = new Roo.data.Connection();
8850 url : this.form.progressUrl,
8855 success : function(req){
8856 //console.log(data);
8860 rdata = Roo.decode(req.responseText)
8862 Roo.log("Invalid data from server..");
8866 if (!rdata || !rdata.success) {
8868 Roo.MessageBox.alert(Roo.encode(rdata));
8871 var data = rdata.data;
8873 if (this.uploadComplete) {
8874 Roo.MessageBox.hide();
8879 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
8880 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
8883 this.uploadProgress.defer(2000,this);
8886 failure: function(data) {
8887 Roo.log('progress url failed ');
8898 // run get Values on the form, so it syncs any secondary forms.
8899 this.form.getValues();
8901 var o = this.options;
8902 var method = this.getMethod();
8903 var isPost = method == 'POST';
8904 if(o.clientValidation === false || this.form.isValid()){
8906 if (this.form.progressUrl) {
8907 this.form.findField('UPLOAD_IDENTIFIER').setValue(
8908 (new Date() * 1) + '' + Math.random());
8913 Roo.Ajax.request(Roo.apply(this.createCallback(), {
8914 form:this.form.el.dom,
8915 url:this.getUrl(!isPost),
8917 params:isPost ? this.getParams() : null,
8918 isUpload: this.form.fileUpload,
8919 formData : this.form.formData
8922 this.uploadProgress();
8924 }else if (o.clientValidation !== false){ // client validation failed
8925 this.failureType = Roo.form.Action.CLIENT_INVALID;
8926 this.form.afterAction(this, false);
8930 success : function(response)
8932 this.uploadComplete= true;
8933 if (this.haveProgress) {
8934 Roo.MessageBox.hide();
8938 var result = this.processResponse(response);
8939 if(result === true || result.success){
8940 this.form.afterAction(this, true);
8944 this.form.markInvalid(result.errors);
8945 this.failureType = Roo.form.Action.SERVER_INVALID;
8947 this.form.afterAction(this, false);
8949 failure : function(response)
8951 this.uploadComplete= true;
8952 if (this.haveProgress) {
8953 Roo.MessageBox.hide();
8956 this.response = response;
8957 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8958 this.form.afterAction(this, false);
8961 handleResponse : function(response){
8962 if(this.form.errorReader){
8963 var rs = this.form.errorReader.read(response);
8966 for(var i = 0, len = rs.records.length; i < len; i++) {
8967 var r = rs.records[i];
8971 if(errors.length < 1){
8975 success : rs.success,
8981 ret = Roo.decode(response.responseText);
8985 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8995 Roo.form.Action.Load = function(form, options){
8996 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8997 this.reader = this.form.reader;
9000 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
9005 Roo.Ajax.request(Roo.apply(
9006 this.createCallback(), {
9007 method:this.getMethod(),
9008 url:this.getUrl(false),
9009 params:this.getParams()
9013 success : function(response){
9015 var result = this.processResponse(response);
9016 if(result === true || !result.success || !result.data){
9017 this.failureType = Roo.form.Action.LOAD_FAILURE;
9018 this.form.afterAction(this, false);
9021 this.form.clearInvalid();
9022 this.form.setValues(result.data);
9023 this.form.afterAction(this, true);
9026 handleResponse : function(response){
9027 if(this.form.reader){
9028 var rs = this.form.reader.read(response);
9029 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
9031 success : rs.success,
9035 return Roo.decode(response.responseText);
9039 Roo.form.Action.ACTION_TYPES = {
9040 'load' : Roo.form.Action.Load,
9041 'submit' : Roo.form.Action.Submit
9050 * @class Roo.bootstrap.Form
9051 * @extends Roo.bootstrap.Component
9052 * Bootstrap Form class
9053 * @cfg {String} method GET | POST (default POST)
9054 * @cfg {String} labelAlign top | left (default top)
9055 * @cfg {String} align left | right - for navbars
9056 * @cfg {Boolean} loadMask load mask when submit (default true)
9061 * @param {Object} config The config object
9065 Roo.bootstrap.Form = function(config){
9067 Roo.bootstrap.Form.superclass.constructor.call(this, config);
9069 Roo.bootstrap.Form.popover.apply();
9073 * @event clientvalidation
9074 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
9075 * @param {Form} this
9076 * @param {Boolean} valid true if the form has passed client-side validation
9078 clientvalidation: true,
9080 * @event beforeaction
9081 * Fires before any action is performed. Return false to cancel the action.
9082 * @param {Form} this
9083 * @param {Action} action The action to be performed
9087 * @event actionfailed
9088 * Fires when an action fails.
9089 * @param {Form} this
9090 * @param {Action} action The action that failed
9092 actionfailed : true,
9094 * @event actioncomplete
9095 * Fires when an action is completed.
9096 * @param {Form} this
9097 * @param {Action} action The action that completed
9099 actioncomplete : true
9103 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
9106 * @cfg {String} method
9107 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
9112 * The URL to use for form actions if one isn't supplied in the action options.
9115 * @cfg {Boolean} fileUpload
9116 * Set to true if this form is a file upload.
9120 * @cfg {Object} baseParams
9121 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
9125 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
9129 * @cfg {Sting} align (left|right) for navbar forms
9134 activeAction : null,
9137 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
9138 * element by passing it or its id or mask the form itself by passing in true.
9141 waitMsgTarget : false,
9146 * @cfg {Boolean} errorMask (true|false) default false
9151 * @cfg {Number} maskOffset Default 100
9156 * @cfg {Boolean} maskBody
9160 getAutoCreate : function(){
9164 method : this.method || 'POST',
9165 id : this.id || Roo.id(),
9168 if (this.parent().xtype.match(/^Nav/)) {
9169 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
9173 if (this.labelAlign == 'left' ) {
9174 cfg.cls += ' form-horizontal';
9180 initEvents : function()
9182 this.el.on('submit', this.onSubmit, this);
9183 // this was added as random key presses on the form where triggering form submit.
9184 this.el.on('keypress', function(e) {
9185 if (e.getCharCode() != 13) {
9188 // we might need to allow it for textareas.. and some other items.
9189 // check e.getTarget().
9191 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
9195 Roo.log("keypress blocked");
9203 onSubmit : function(e){
9208 * Returns true if client-side validation on the form is successful.
9211 isValid : function(){
9212 var items = this.getItems();
9216 items.each(function(f){
9222 Roo.log('invalid field: ' + f.name);
9226 if(!target && f.el.isVisible(true)){
9232 if(this.errorMask && !valid){
9233 Roo.bootstrap.Form.popover.mask(this, target);
9240 * Returns true if any fields in this form have changed since their original load.
9243 isDirty : function(){
9245 var items = this.getItems();
9246 items.each(function(f){
9256 * Performs a predefined action (submit or load) or custom actions you define on this form.
9257 * @param {String} actionName The name of the action type
9258 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
9259 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
9260 * accept other config options):
9262 Property Type Description
9263 ---------------- --------------- ----------------------------------------------------------------------------------
9264 url String The url for the action (defaults to the form's url)
9265 method String The form method to use (defaults to the form's method, or POST if not defined)
9266 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
9267 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
9268 validate the form on the client (defaults to false)
9270 * @return {BasicForm} this
9272 doAction : function(action, options){
9273 if(typeof action == 'string'){
9274 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
9276 if(this.fireEvent('beforeaction', this, action) !== false){
9277 this.beforeAction(action);
9278 action.run.defer(100, action);
9284 beforeAction : function(action){
9285 var o = action.options;
9290 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
9292 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9295 // not really supported yet.. ??
9297 //if(this.waitMsgTarget === true){
9298 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9299 //}else if(this.waitMsgTarget){
9300 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
9301 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
9303 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
9309 afterAction : function(action, success){
9310 this.activeAction = null;
9311 var o = action.options;
9316 Roo.get(document.body).unmask();
9322 //if(this.waitMsgTarget === true){
9323 // this.el.unmask();
9324 //}else if(this.waitMsgTarget){
9325 // this.waitMsgTarget.unmask();
9327 // Roo.MessageBox.updateProgress(1);
9328 // Roo.MessageBox.hide();
9335 Roo.callback(o.success, o.scope, [this, action]);
9336 this.fireEvent('actioncomplete', this, action);
9340 // failure condition..
9341 // we have a scenario where updates need confirming.
9342 // eg. if a locking scenario exists..
9343 // we look for { errors : { needs_confirm : true }} in the response.
9345 (typeof(action.result) != 'undefined') &&
9346 (typeof(action.result.errors) != 'undefined') &&
9347 (typeof(action.result.errors.needs_confirm) != 'undefined')
9350 Roo.log("not supported yet");
9353 Roo.MessageBox.confirm(
9354 "Change requires confirmation",
9355 action.result.errorMsg,
9360 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
9370 Roo.callback(o.failure, o.scope, [this, action]);
9371 // show an error message if no failed handler is set..
9372 if (!this.hasListener('actionfailed')) {
9373 Roo.log("need to add dialog support");
9375 Roo.MessageBox.alert("Error",
9376 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
9377 action.result.errorMsg :
9378 "Saving Failed, please check your entries or try again"
9383 this.fireEvent('actionfailed', this, action);
9388 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
9389 * @param {String} id The value to search for
9392 findField : function(id){
9393 var items = this.getItems();
9394 var field = items.get(id);
9396 items.each(function(f){
9397 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
9404 return field || null;
9407 * Mark fields in this form invalid in bulk.
9408 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
9409 * @return {BasicForm} this
9411 markInvalid : function(errors){
9412 if(errors instanceof Array){
9413 for(var i = 0, len = errors.length; i < len; i++){
9414 var fieldError = errors[i];
9415 var f = this.findField(fieldError.id);
9417 f.markInvalid(fieldError.msg);
9423 if(typeof errors[id] != 'function' && (field = this.findField(id))){
9424 field.markInvalid(errors[id]);
9428 //Roo.each(this.childForms || [], function (f) {
9429 // f.markInvalid(errors);
9436 * Set values for fields in this form in bulk.
9437 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
9438 * @return {BasicForm} this
9440 setValues : function(values){
9441 if(values instanceof Array){ // array of objects
9442 for(var i = 0, len = values.length; i < len; i++){
9444 var f = this.findField(v.id);
9446 f.setValue(v.value);
9447 if(this.trackResetOnLoad){
9448 f.originalValue = f.getValue();
9452 }else{ // object hash
9455 if(typeof values[id] != 'function' && (field = this.findField(id))){
9457 if (field.setFromData &&
9459 field.displayField &&
9460 // combos' with local stores can
9461 // be queried via setValue()
9462 // to set their value..
9463 (field.store && !field.store.isLocal)
9467 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
9468 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
9469 field.setFromData(sd);
9471 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
9473 field.setFromData(values);
9476 field.setValue(values[id]);
9480 if(this.trackResetOnLoad){
9481 field.originalValue = field.getValue();
9487 //Roo.each(this.childForms || [], function (f) {
9488 // f.setValues(values);
9495 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
9496 * they are returned as an array.
9497 * @param {Boolean} asString
9500 getValues : function(asString){
9501 //if (this.childForms) {
9502 // copy values from the child forms
9503 // Roo.each(this.childForms, function (f) {
9504 // this.setValues(f.getValues());
9510 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
9511 if(asString === true){
9514 return Roo.urlDecode(fs);
9518 * Returns the fields in this form as an object with key/value pairs.
9519 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
9522 getFieldValues : function(with_hidden)
9524 var items = this.getItems();
9526 items.each(function(f){
9532 var v = f.getValue();
9534 if (f.inputType =='radio') {
9535 if (typeof(ret[f.getName()]) == 'undefined') {
9536 ret[f.getName()] = ''; // empty..
9539 if (!f.el.dom.checked) {
9547 if(f.xtype == 'MoneyField'){
9548 ret[f.currencyName] = f.getCurrency();
9551 // not sure if this supported any more..
9552 if ((typeof(v) == 'object') && f.getRawValue) {
9553 v = f.getRawValue() ; // dates..
9555 // combo boxes where name != hiddenName...
9556 if (f.name !== false && f.name != '' && f.name != f.getName()) {
9557 ret[f.name] = f.getRawValue();
9559 ret[f.getName()] = v;
9566 * Clears all invalid messages in this form.
9567 * @return {BasicForm} this
9569 clearInvalid : function(){
9570 var items = this.getItems();
9572 items.each(function(f){
9581 * @return {BasicForm} this
9584 var items = this.getItems();
9585 items.each(function(f){
9589 Roo.each(this.childForms || [], function (f) {
9597 getItems : function()
9599 var r=new Roo.util.MixedCollection(false, function(o){
9600 return o.id || (o.id = Roo.id());
9602 var iter = function(el) {
9609 Roo.each(el.items,function(e) {
9618 hideFields : function(items)
9620 Roo.each(items, function(i){
9622 var f = this.findField(i);
9633 showFields : function(items)
9635 Roo.each(items, function(i){
9637 var f = this.findField(i);
9650 Roo.apply(Roo.bootstrap.Form, {
9677 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
9678 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
9679 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
9680 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
9683 this.maskEl.top.enableDisplayMode("block");
9684 this.maskEl.left.enableDisplayMode("block");
9685 this.maskEl.bottom.enableDisplayMode("block");
9686 this.maskEl.right.enableDisplayMode("block");
9688 this.toolTip = new Roo.bootstrap.Tooltip({
9689 cls : 'roo-form-error-popover',
9691 'left' : ['r-l', [-2,0], 'right'],
9692 'right' : ['l-r', [2,0], 'left'],
9693 'bottom' : ['tl-bl', [0,2], 'top'],
9694 'top' : [ 'bl-tl', [0,-2], 'bottom']
9698 this.toolTip.render(Roo.get(document.body));
9700 this.toolTip.el.enableDisplayMode("block");
9702 Roo.get(document.body).on('click', function(){
9706 Roo.get(document.body).on('touchstart', function(){
9710 this.isApplied = true
9713 mask : function(form, target)
9717 this.target = target;
9719 if(!this.form.errorMask || !target.el){
9723 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
9725 Roo.log(scrollable);
9727 var ot = this.target.el.calcOffsetsTo(scrollable);
9729 var scrollTo = ot[1] - this.form.maskOffset;
9731 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
9733 scrollable.scrollTo('top', scrollTo);
9735 var box = this.target.el.getBox();
9737 var zIndex = Roo.bootstrap.Modal.zIndex++;
9740 this.maskEl.top.setStyle('position', 'absolute');
9741 this.maskEl.top.setStyle('z-index', zIndex);
9742 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
9743 this.maskEl.top.setLeft(0);
9744 this.maskEl.top.setTop(0);
9745 this.maskEl.top.show();
9747 this.maskEl.left.setStyle('position', 'absolute');
9748 this.maskEl.left.setStyle('z-index', zIndex);
9749 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
9750 this.maskEl.left.setLeft(0);
9751 this.maskEl.left.setTop(box.y - this.padding);
9752 this.maskEl.left.show();
9754 this.maskEl.bottom.setStyle('position', 'absolute');
9755 this.maskEl.bottom.setStyle('z-index', zIndex);
9756 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
9757 this.maskEl.bottom.setLeft(0);
9758 this.maskEl.bottom.setTop(box.bottom + this.padding);
9759 this.maskEl.bottom.show();
9761 this.maskEl.right.setStyle('position', 'absolute');
9762 this.maskEl.right.setStyle('z-index', zIndex);
9763 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
9764 this.maskEl.right.setLeft(box.right + this.padding);
9765 this.maskEl.right.setTop(box.y - this.padding);
9766 this.maskEl.right.show();
9768 this.toolTip.bindEl = this.target.el;
9770 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
9772 var tip = this.target.blankText;
9774 if(this.target.getValue() !== '' ) {
9776 if (this.target.invalidText.length) {
9777 tip = this.target.invalidText;
9778 } else if (this.target.regexText.length){
9779 tip = this.target.regexText;
9783 this.toolTip.show(tip);
9785 this.intervalID = window.setInterval(function() {
9786 Roo.bootstrap.Form.popover.unmask();
9789 window.onwheel = function(){ return false;};
9791 (function(){ this.isMasked = true; }).defer(500, this);
9797 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
9801 this.maskEl.top.setStyle('position', 'absolute');
9802 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
9803 this.maskEl.top.hide();
9805 this.maskEl.left.setStyle('position', 'absolute');
9806 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
9807 this.maskEl.left.hide();
9809 this.maskEl.bottom.setStyle('position', 'absolute');
9810 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
9811 this.maskEl.bottom.hide();
9813 this.maskEl.right.setStyle('position', 'absolute');
9814 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
9815 this.maskEl.right.hide();
9817 this.toolTip.hide();
9819 this.toolTip.el.hide();
9821 window.onwheel = function(){ return true;};
9823 if(this.intervalID){
9824 window.clearInterval(this.intervalID);
9825 this.intervalID = false;
9828 this.isMasked = false;
9838 * Ext JS Library 1.1.1
9839 * Copyright(c) 2006-2007, Ext JS, LLC.
9841 * Originally Released Under LGPL - original licence link has changed is not relivant.
9844 * <script type="text/javascript">
9847 * @class Roo.form.VTypes
9848 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
9851 Roo.form.VTypes = function(){
9852 // closure these in so they are only created once.
9853 var alpha = /^[a-zA-Z_]+$/;
9854 var alphanum = /^[a-zA-Z0-9_]+$/;
9855 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
9856 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
9858 // All these messages and functions are configurable
9861 * The function used to validate email addresses
9862 * @param {String} value The email address
9864 'email' : function(v){
9865 return email.test(v);
9868 * The error text to display when the email validation function returns false
9871 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
9873 * The keystroke filter mask to be applied on email input
9876 'emailMask' : /[a-z0-9_\.\-@]/i,
9879 * The function used to validate URLs
9880 * @param {String} value The URL
9882 'url' : function(v){
9886 * The error text to display when the url validation function returns false
9889 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
9892 * The function used to validate alpha values
9893 * @param {String} value The value
9895 'alpha' : function(v){
9896 return alpha.test(v);
9899 * The error text to display when the alpha validation function returns false
9902 'alphaText' : 'This field should only contain letters and _',
9904 * The keystroke filter mask to be applied on alpha input
9907 'alphaMask' : /[a-z_]/i,
9910 * The function used to validate alphanumeric values
9911 * @param {String} value The value
9913 'alphanum' : function(v){
9914 return alphanum.test(v);
9917 * The error text to display when the alphanumeric validation function returns false
9920 'alphanumText' : 'This field should only contain letters, numbers and _',
9922 * The keystroke filter mask to be applied on alphanumeric input
9925 'alphanumMask' : /[a-z0-9_]/i
9935 * @class Roo.bootstrap.Input
9936 * @extends Roo.bootstrap.Component
9937 * Bootstrap Input class
9938 * @cfg {Boolean} disabled is it disabled
9939 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9940 * @cfg {String} name name of the input
9941 * @cfg {string} fieldLabel - the label associated
9942 * @cfg {string} placeholder - placeholder to put in text.
9943 * @cfg {string} before - input group add on before
9944 * @cfg {string} after - input group add on after
9945 * @cfg {string} size - (lg|sm) or leave empty..
9946 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9947 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9948 * @cfg {Number} md colspan out of 12 for computer-sized screens
9949 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9950 * @cfg {string} value default value of the input
9951 * @cfg {Number} labelWidth set the width of label
9952 * @cfg {Number} labellg set the width of label (1-12)
9953 * @cfg {Number} labelmd set the width of label (1-12)
9954 * @cfg {Number} labelsm set the width of label (1-12)
9955 * @cfg {Number} labelxs set the width of label (1-12)
9956 * @cfg {String} labelAlign (top|left)
9957 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9958 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9959 * @cfg {String} indicatorpos (left|right) default left
9960 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9961 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9963 * @cfg {String} align (left|center|right) Default left
9964 * @cfg {Boolean} forceFeedback (true|false) Default false
9967 * Create a new Input
9968 * @param {Object} config The config object
9971 Roo.bootstrap.Input = function(config){
9973 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9978 * Fires when this field receives input focus.
9979 * @param {Roo.form.Field} this
9984 * Fires when this field loses input focus.
9985 * @param {Roo.form.Field} this
9990 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9991 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9992 * @param {Roo.form.Field} this
9993 * @param {Roo.EventObject} e The event object
9998 * Fires just before the field blurs if the field value has changed.
9999 * @param {Roo.form.Field} this
10000 * @param {Mixed} newValue The new value
10001 * @param {Mixed} oldValue The original value
10006 * Fires after the field has been marked as invalid.
10007 * @param {Roo.form.Field} this
10008 * @param {String} msg The validation message
10013 * Fires after the field has been validated with no errors.
10014 * @param {Roo.form.Field} this
10019 * Fires after the key up
10020 * @param {Roo.form.Field} this
10021 * @param {Roo.EventObject} e The event Object
10027 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
10029 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
10030 automatic validation (defaults to "keyup").
10032 validationEvent : "keyup",
10034 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
10036 validateOnBlur : true,
10038 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
10040 validationDelay : 250,
10042 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
10044 focusClass : "x-form-focus", // not needed???
10048 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10050 invalidClass : "has-warning",
10053 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10055 validClass : "has-success",
10058 * @cfg {Boolean} hasFeedback (true|false) default true
10060 hasFeedback : true,
10063 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10065 invalidFeedbackClass : "glyphicon-warning-sign",
10068 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10070 validFeedbackClass : "glyphicon-ok",
10073 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
10075 selectOnFocus : false,
10078 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
10082 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
10087 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
10089 disableKeyFilter : false,
10092 * @cfg {Boolean} disabled True to disable the field (defaults to false).
10096 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
10100 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
10102 blankText : "Please complete this mandatory field",
10105 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
10109 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
10111 maxLength : Number.MAX_VALUE,
10113 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
10115 minLengthText : "The minimum length for this field is {0}",
10117 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
10119 maxLengthText : "The maximum length for this field is {0}",
10123 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
10124 * If available, this function will be called only after the basic validators all return true, and will be passed the
10125 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
10129 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
10130 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
10131 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
10135 * @cfg {String} regexText -- Depricated - use Invalid Text
10140 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
10146 autocomplete: false,
10150 inputType : 'text',
10153 placeholder: false,
10158 preventMark: false,
10159 isFormField : true,
10162 labelAlign : false,
10165 formatedValue : false,
10166 forceFeedback : false,
10168 indicatorpos : 'left',
10178 parentLabelAlign : function()
10181 while (parent.parent()) {
10182 parent = parent.parent();
10183 if (typeof(parent.labelAlign) !='undefined') {
10184 return parent.labelAlign;
10191 getAutoCreate : function()
10193 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10199 if(this.inputType != 'hidden'){
10200 cfg.cls = 'form-group' //input-group
10206 type : this.inputType,
10207 value : this.value,
10208 cls : 'form-control',
10209 placeholder : this.placeholder || '',
10210 autocomplete : this.autocomplete || 'new-password'
10213 if(this.capture.length){
10214 input.capture = this.capture;
10217 if(this.accept.length){
10218 input.accept = this.accept + "/*";
10222 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
10225 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10226 input.maxLength = this.maxLength;
10229 if (this.disabled) {
10230 input.disabled=true;
10233 if (this.readOnly) {
10234 input.readonly=true;
10238 input.name = this.name;
10242 input.cls += ' input-' + this.size;
10246 ['xs','sm','md','lg'].map(function(size){
10247 if (settings[size]) {
10248 cfg.cls += ' col-' + size + '-' + settings[size];
10252 var inputblock = input;
10256 cls: 'glyphicon form-control-feedback'
10259 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10262 cls : 'has-feedback',
10270 if (this.before || this.after) {
10273 cls : 'input-group',
10277 if (this.before && typeof(this.before) == 'string') {
10279 inputblock.cn.push({
10281 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
10285 if (this.before && typeof(this.before) == 'object') {
10286 this.before = Roo.factory(this.before);
10288 inputblock.cn.push({
10290 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
10291 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10295 inputblock.cn.push(input);
10297 if (this.after && typeof(this.after) == 'string') {
10298 inputblock.cn.push({
10300 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
10304 if (this.after && typeof(this.after) == 'object') {
10305 this.after = Roo.factory(this.after);
10307 inputblock.cn.push({
10309 cls : 'roo-input-after input-group-append input-group-text input-group-' +
10310 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10314 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10315 inputblock.cls += ' has-feedback';
10316 inputblock.cn.push(feedback);
10321 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10322 tooltip : 'This field is required'
10324 if (Roo.bootstrap.version == 4) {
10327 style : 'display-none'
10330 if (align ==='left' && this.fieldLabel.length) {
10332 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10339 cls : 'control-label col-form-label',
10340 html : this.fieldLabel
10351 var labelCfg = cfg.cn[1];
10352 var contentCfg = cfg.cn[2];
10354 if(this.indicatorpos == 'right'){
10359 cls : 'control-label col-form-label',
10363 html : this.fieldLabel
10377 labelCfg = cfg.cn[0];
10378 contentCfg = cfg.cn[1];
10382 if(this.labelWidth > 12){
10383 labelCfg.style = "width: " + this.labelWidth + 'px';
10386 if(this.labelWidth < 13 && this.labelmd == 0){
10387 this.labelmd = this.labelWidth;
10390 if(this.labellg > 0){
10391 labelCfg.cls += ' col-lg-' + this.labellg;
10392 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10395 if(this.labelmd > 0){
10396 labelCfg.cls += ' col-md-' + this.labelmd;
10397 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10400 if(this.labelsm > 0){
10401 labelCfg.cls += ' col-sm-' + this.labelsm;
10402 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10405 if(this.labelxs > 0){
10406 labelCfg.cls += ' col-xs-' + this.labelxs;
10407 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10411 } else if ( this.fieldLabel.length) {
10416 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10417 tooltip : 'This field is required'
10421 //cls : 'input-group-addon',
10422 html : this.fieldLabel
10430 if(this.indicatorpos == 'right'){
10435 //cls : 'input-group-addon',
10436 html : this.fieldLabel
10441 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10442 tooltip : 'This field is required'
10462 if (this.parentType === 'Navbar' && this.parent().bar) {
10463 cfg.cls += ' navbar-form';
10466 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
10467 // on BS4 we do this only if not form
10468 cfg.cls += ' navbar-form';
10476 * return the real input element.
10478 inputEl: function ()
10480 return this.el.select('input.form-control',true).first();
10483 tooltipEl : function()
10485 return this.inputEl();
10488 indicatorEl : function()
10490 if (Roo.bootstrap.version == 4) {
10491 return false; // not enabled in v4 yet.
10494 var indicator = this.el.select('i.roo-required-indicator',true).first();
10504 setDisabled : function(v)
10506 var i = this.inputEl().dom;
10508 i.removeAttribute('disabled');
10512 i.setAttribute('disabled','true');
10514 initEvents : function()
10517 this.inputEl().on("keydown" , this.fireKey, this);
10518 this.inputEl().on("focus", this.onFocus, this);
10519 this.inputEl().on("blur", this.onBlur, this);
10521 this.inputEl().relayEvent('keyup', this);
10523 this.indicator = this.indicatorEl();
10525 if(this.indicator){
10526 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
10529 // reference to original value for reset
10530 this.originalValue = this.getValue();
10531 //Roo.form.TextField.superclass.initEvents.call(this);
10532 if(this.validationEvent == 'keyup'){
10533 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
10534 this.inputEl().on('keyup', this.filterValidation, this);
10536 else if(this.validationEvent !== false){
10537 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
10540 if(this.selectOnFocus){
10541 this.on("focus", this.preFocus, this);
10544 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
10545 this.inputEl().on("keypress", this.filterKeys, this);
10547 this.inputEl().relayEvent('keypress', this);
10550 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
10551 this.el.on("click", this.autoSize, this);
10554 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
10555 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
10558 if (typeof(this.before) == 'object') {
10559 this.before.render(this.el.select('.roo-input-before',true).first());
10561 if (typeof(this.after) == 'object') {
10562 this.after.render(this.el.select('.roo-input-after',true).first());
10565 this.inputEl().on('change', this.onChange, this);
10568 filterValidation : function(e){
10569 if(!e.isNavKeyPress()){
10570 this.validationTask.delay(this.validationDelay);
10574 * Validates the field value
10575 * @return {Boolean} True if the value is valid, else false
10577 validate : function(){
10578 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
10579 if(this.disabled || this.validateValue(this.getRawValue())){
10584 this.markInvalid();
10590 * Validates a value according to the field's validation rules and marks the field as invalid
10591 * if the validation fails
10592 * @param {Mixed} value The value to validate
10593 * @return {Boolean} True if the value is valid, else false
10595 validateValue : function(value)
10597 if(this.getVisibilityEl().hasClass('hidden')){
10601 if(value.length < 1) { // if it's blank
10602 if(this.allowBlank){
10608 if(value.length < this.minLength){
10611 if(value.length > this.maxLength){
10615 var vt = Roo.form.VTypes;
10616 if(!vt[this.vtype](value, this)){
10620 if(typeof this.validator == "function"){
10621 var msg = this.validator(value);
10625 if (typeof(msg) == 'string') {
10626 this.invalidText = msg;
10630 if(this.regex && !this.regex.test(value)){
10638 fireKey : function(e){
10639 //Roo.log('field ' + e.getKey());
10640 if(e.isNavKeyPress()){
10641 this.fireEvent("specialkey", this, e);
10644 focus : function (selectText){
10646 this.inputEl().focus();
10647 if(selectText === true){
10648 this.inputEl().dom.select();
10654 onFocus : function(){
10655 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
10656 // this.el.addClass(this.focusClass);
10658 if(!this.hasFocus){
10659 this.hasFocus = true;
10660 this.startValue = this.getValue();
10661 this.fireEvent("focus", this);
10665 beforeBlur : Roo.emptyFn,
10669 onBlur : function(){
10671 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
10672 //this.el.removeClass(this.focusClass);
10674 this.hasFocus = false;
10675 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
10678 var v = this.getValue();
10679 if(String(v) !== String(this.startValue)){
10680 this.fireEvent('change', this, v, this.startValue);
10682 this.fireEvent("blur", this);
10685 onChange : function(e)
10687 var v = this.getValue();
10688 if(String(v) !== String(this.startValue)){
10689 this.fireEvent('change', this, v, this.startValue);
10695 * Resets the current field value to the originally loaded value and clears any validation messages
10697 reset : function(){
10698 this.setValue(this.originalValue);
10702 * Returns the name of the field
10703 * @return {Mixed} name The name field
10705 getName: function(){
10709 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
10710 * @return {Mixed} value The field value
10712 getValue : function(){
10714 var v = this.inputEl().getValue();
10719 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
10720 * @return {Mixed} value The field value
10722 getRawValue : function(){
10723 var v = this.inputEl().getValue();
10729 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
10730 * @param {Mixed} value The value to set
10732 setRawValue : function(v){
10733 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
10736 selectText : function(start, end){
10737 var v = this.getRawValue();
10739 start = start === undefined ? 0 : start;
10740 end = end === undefined ? v.length : end;
10741 var d = this.inputEl().dom;
10742 if(d.setSelectionRange){
10743 d.setSelectionRange(start, end);
10744 }else if(d.createTextRange){
10745 var range = d.createTextRange();
10746 range.moveStart("character", start);
10747 range.moveEnd("character", v.length-end);
10754 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
10755 * @param {Mixed} value The value to set
10757 setValue : function(v){
10760 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
10766 processValue : function(value){
10767 if(this.stripCharsRe){
10768 var newValue = value.replace(this.stripCharsRe, '');
10769 if(newValue !== value){
10770 this.setRawValue(newValue);
10777 preFocus : function(){
10779 if(this.selectOnFocus){
10780 this.inputEl().dom.select();
10783 filterKeys : function(e){
10784 var k = e.getKey();
10785 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
10788 var c = e.getCharCode(), cc = String.fromCharCode(c);
10789 if(Roo.isIE && (e.isSpecialKey() || !cc)){
10792 if(!this.maskRe.test(cc)){
10797 * Clear any invalid styles/messages for this field
10799 clearInvalid : function(){
10801 if(!this.el || this.preventMark){ // not rendered
10806 this.el.removeClass([this.invalidClass, 'is-invalid']);
10808 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10810 var feedback = this.el.select('.form-control-feedback', true).first();
10813 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10818 if(this.indicator){
10819 this.indicator.removeClass('visible');
10820 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10823 this.fireEvent('valid', this);
10827 * Mark this field as valid
10829 markValid : function()
10831 if(!this.el || this.preventMark){ // not rendered...
10835 this.el.removeClass([this.invalidClass, this.validClass]);
10836 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10838 var feedback = this.el.select('.form-control-feedback', true).first();
10841 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10844 if(this.indicator){
10845 this.indicator.removeClass('visible');
10846 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10853 if(this.allowBlank && !this.getRawValue().length){
10856 if (Roo.bootstrap.version == 3) {
10857 this.el.addClass(this.validClass);
10859 this.inputEl().addClass('is-valid');
10862 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10864 var feedback = this.el.select('.form-control-feedback', true).first();
10867 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10868 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10873 this.fireEvent('valid', this);
10877 * Mark this field as invalid
10878 * @param {String} msg The validation message
10880 markInvalid : function(msg)
10882 if(!this.el || this.preventMark){ // not rendered
10886 this.el.removeClass([this.invalidClass, this.validClass]);
10887 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10889 var feedback = this.el.select('.form-control-feedback', true).first();
10892 this.el.select('.form-control-feedback', true).first().removeClass(
10893 [this.invalidFeedbackClass, this.validFeedbackClass]);
10900 if(this.allowBlank && !this.getRawValue().length){
10904 if(this.indicator){
10905 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10906 this.indicator.addClass('visible');
10908 if (Roo.bootstrap.version == 3) {
10909 this.el.addClass(this.invalidClass);
10911 this.inputEl().addClass('is-invalid');
10916 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10918 var feedback = this.el.select('.form-control-feedback', true).first();
10921 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10923 if(this.getValue().length || this.forceFeedback){
10924 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10931 this.fireEvent('invalid', this, msg);
10934 SafariOnKeyDown : function(event)
10936 // this is a workaround for a password hang bug on chrome/ webkit.
10937 if (this.inputEl().dom.type != 'password') {
10941 var isSelectAll = false;
10943 if(this.inputEl().dom.selectionEnd > 0){
10944 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10946 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10947 event.preventDefault();
10952 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10954 event.preventDefault();
10955 // this is very hacky as keydown always get's upper case.
10957 var cc = String.fromCharCode(event.getCharCode());
10958 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10962 adjustWidth : function(tag, w){
10963 tag = tag.toLowerCase();
10964 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10965 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10966 if(tag == 'input'){
10969 if(tag == 'textarea'){
10972 }else if(Roo.isOpera){
10973 if(tag == 'input'){
10976 if(tag == 'textarea'){
10984 setFieldLabel : function(v)
10986 if(!this.rendered){
10990 if(this.indicatorEl()){
10991 var ar = this.el.select('label > span',true);
10993 if (ar.elements.length) {
10994 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10995 this.fieldLabel = v;
10999 var br = this.el.select('label',true);
11001 if(br.elements.length) {
11002 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11003 this.fieldLabel = v;
11007 Roo.log('Cannot Found any of label > span || label in input');
11011 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11012 this.fieldLabel = v;
11027 * @class Roo.bootstrap.TextArea
11028 * @extends Roo.bootstrap.Input
11029 * Bootstrap TextArea class
11030 * @cfg {Number} cols Specifies the visible width of a text area
11031 * @cfg {Number} rows Specifies the visible number of lines in a text area
11032 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
11033 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
11034 * @cfg {string} html text
11037 * Create a new TextArea
11038 * @param {Object} config The config object
11041 Roo.bootstrap.TextArea = function(config){
11042 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
11046 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
11056 getAutoCreate : function(){
11058 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11064 if(this.inputType != 'hidden'){
11065 cfg.cls = 'form-group' //input-group
11073 value : this.value || '',
11074 html: this.html || '',
11075 cls : 'form-control',
11076 placeholder : this.placeholder || ''
11080 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
11081 input.maxLength = this.maxLength;
11085 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
11089 input.cols = this.cols;
11092 if (this.readOnly) {
11093 input.readonly = true;
11097 input.name = this.name;
11101 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
11105 ['xs','sm','md','lg'].map(function(size){
11106 if (settings[size]) {
11107 cfg.cls += ' col-' + size + '-' + settings[size];
11111 var inputblock = input;
11113 if(this.hasFeedback && !this.allowBlank){
11117 cls: 'glyphicon form-control-feedback'
11121 cls : 'has-feedback',
11130 if (this.before || this.after) {
11133 cls : 'input-group',
11137 inputblock.cn.push({
11139 cls : 'input-group-addon',
11144 inputblock.cn.push(input);
11146 if(this.hasFeedback && !this.allowBlank){
11147 inputblock.cls += ' has-feedback';
11148 inputblock.cn.push(feedback);
11152 inputblock.cn.push({
11154 cls : 'input-group-addon',
11161 if (align ==='left' && this.fieldLabel.length) {
11166 cls : 'control-label',
11167 html : this.fieldLabel
11178 if(this.labelWidth > 12){
11179 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
11182 if(this.labelWidth < 13 && this.labelmd == 0){
11183 this.labelmd = this.labelWidth;
11186 if(this.labellg > 0){
11187 cfg.cn[0].cls += ' col-lg-' + this.labellg;
11188 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
11191 if(this.labelmd > 0){
11192 cfg.cn[0].cls += ' col-md-' + this.labelmd;
11193 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
11196 if(this.labelsm > 0){
11197 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
11198 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
11201 if(this.labelxs > 0){
11202 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
11203 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
11206 } else if ( this.fieldLabel.length) {
11211 //cls : 'input-group-addon',
11212 html : this.fieldLabel
11230 if (this.disabled) {
11231 input.disabled=true;
11238 * return the real textarea element.
11240 inputEl: function ()
11242 return this.el.select('textarea.form-control',true).first();
11246 * Clear any invalid styles/messages for this field
11248 clearInvalid : function()
11251 if(!this.el || this.preventMark){ // not rendered
11255 var label = this.el.select('label', true).first();
11256 var icon = this.el.select('i.fa-star', true).first();
11261 this.el.removeClass( this.validClass);
11262 this.inputEl().removeClass('is-invalid');
11264 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11266 var feedback = this.el.select('.form-control-feedback', true).first();
11269 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11274 this.fireEvent('valid', this);
11278 * Mark this field as valid
11280 markValid : function()
11282 if(!this.el || this.preventMark){ // not rendered
11286 this.el.removeClass([this.invalidClass, this.validClass]);
11287 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11289 var feedback = this.el.select('.form-control-feedback', true).first();
11292 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11295 if(this.disabled || this.allowBlank){
11299 var label = this.el.select('label', true).first();
11300 var icon = this.el.select('i.fa-star', true).first();
11305 if (Roo.bootstrap.version == 3) {
11306 this.el.addClass(this.validClass);
11308 this.inputEl().addClass('is-valid');
11312 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11314 var feedback = this.el.select('.form-control-feedback', true).first();
11317 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11318 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11323 this.fireEvent('valid', this);
11327 * Mark this field as invalid
11328 * @param {String} msg The validation message
11330 markInvalid : function(msg)
11332 if(!this.el || this.preventMark){ // not rendered
11336 this.el.removeClass([this.invalidClass, this.validClass]);
11337 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11339 var feedback = this.el.select('.form-control-feedback', true).first();
11342 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11345 if(this.disabled || this.allowBlank){
11349 var label = this.el.select('label', true).first();
11350 var icon = this.el.select('i.fa-star', true).first();
11352 if(!this.getValue().length && label && !icon){
11353 this.el.createChild({
11355 cls : 'text-danger fa fa-lg fa-star',
11356 tooltip : 'This field is required',
11357 style : 'margin-right:5px;'
11361 if (Roo.bootstrap.version == 3) {
11362 this.el.addClass(this.invalidClass);
11364 this.inputEl().addClass('is-invalid');
11367 // fixme ... this may be depricated need to test..
11368 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11370 var feedback = this.el.select('.form-control-feedback', true).first();
11373 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11375 if(this.getValue().length || this.forceFeedback){
11376 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11383 this.fireEvent('invalid', this, msg);
11391 * trigger field - base class for combo..
11396 * @class Roo.bootstrap.TriggerField
11397 * @extends Roo.bootstrap.Input
11398 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
11399 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
11400 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
11401 * for which you can provide a custom implementation. For example:
11403 var trigger = new Roo.bootstrap.TriggerField();
11404 trigger.onTriggerClick = myTriggerFn;
11405 trigger.applyTo('my-field');
11408 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
11409 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
11410 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
11411 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
11412 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
11415 * Create a new TriggerField.
11416 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
11417 * to the base TextField)
11419 Roo.bootstrap.TriggerField = function(config){
11420 this.mimicing = false;
11421 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
11424 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
11426 * @cfg {String} triggerClass A CSS class to apply to the trigger
11429 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
11434 * @cfg {Boolean} removable (true|false) special filter default false
11438 /** @cfg {Boolean} grow @hide */
11439 /** @cfg {Number} growMin @hide */
11440 /** @cfg {Number} growMax @hide */
11446 autoSize: Roo.emptyFn,
11450 deferHeight : true,
11453 actionMode : 'wrap',
11458 getAutoCreate : function(){
11460 var align = this.labelAlign || this.parentLabelAlign();
11465 cls: 'form-group' //input-group
11472 type : this.inputType,
11473 cls : 'form-control',
11474 autocomplete: 'new-password',
11475 placeholder : this.placeholder || ''
11479 input.name = this.name;
11482 input.cls += ' input-' + this.size;
11485 if (this.disabled) {
11486 input.disabled=true;
11489 var inputblock = input;
11491 if(this.hasFeedback && !this.allowBlank){
11495 cls: 'glyphicon form-control-feedback'
11498 if(this.removable && !this.editable && !this.tickable){
11500 cls : 'has-feedback',
11506 cls : 'roo-combo-removable-btn close'
11513 cls : 'has-feedback',
11522 if(this.removable && !this.editable && !this.tickable){
11524 cls : 'roo-removable',
11530 cls : 'roo-combo-removable-btn close'
11537 if (this.before || this.after) {
11540 cls : 'input-group',
11544 inputblock.cn.push({
11546 cls : 'input-group-addon input-group-prepend input-group-text',
11551 inputblock.cn.push(input);
11553 if(this.hasFeedback && !this.allowBlank){
11554 inputblock.cls += ' has-feedback';
11555 inputblock.cn.push(feedback);
11559 inputblock.cn.push({
11561 cls : 'input-group-addon input-group-append input-group-text',
11570 var ibwrap = inputblock;
11575 cls: 'roo-select2-choices',
11579 cls: 'roo-select2-search-field',
11591 cls: 'roo-select2-container input-group',
11596 cls: 'form-hidden-field'
11602 if(!this.multiple && this.showToggleBtn){
11608 if (this.caret != false) {
11611 cls: 'fa fa-' + this.caret
11618 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
11620 Roo.bootstrap.version == 3 ? caret : '',
11623 cls: 'combobox-clear',
11637 combobox.cls += ' roo-select2-container-multi';
11641 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
11642 tooltip : 'This field is required'
11644 if (Roo.bootstrap.version == 4) {
11647 style : 'display:none'
11652 if (align ==='left' && this.fieldLabel.length) {
11654 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
11661 cls : 'control-label',
11662 html : this.fieldLabel
11674 var labelCfg = cfg.cn[1];
11675 var contentCfg = cfg.cn[2];
11677 if(this.indicatorpos == 'right'){
11682 cls : 'control-label',
11686 html : this.fieldLabel
11700 labelCfg = cfg.cn[0];
11701 contentCfg = cfg.cn[1];
11704 if(this.labelWidth > 12){
11705 labelCfg.style = "width: " + this.labelWidth + 'px';
11708 if(this.labelWidth < 13 && this.labelmd == 0){
11709 this.labelmd = this.labelWidth;
11712 if(this.labellg > 0){
11713 labelCfg.cls += ' col-lg-' + this.labellg;
11714 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
11717 if(this.labelmd > 0){
11718 labelCfg.cls += ' col-md-' + this.labelmd;
11719 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
11722 if(this.labelsm > 0){
11723 labelCfg.cls += ' col-sm-' + this.labelsm;
11724 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
11727 if(this.labelxs > 0){
11728 labelCfg.cls += ' col-xs-' + this.labelxs;
11729 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
11732 } else if ( this.fieldLabel.length) {
11733 // Roo.log(" label");
11738 //cls : 'input-group-addon',
11739 html : this.fieldLabel
11747 if(this.indicatorpos == 'right'){
11755 html : this.fieldLabel
11769 // Roo.log(" no label && no align");
11776 ['xs','sm','md','lg'].map(function(size){
11777 if (settings[size]) {
11778 cfg.cls += ' col-' + size + '-' + settings[size];
11789 onResize : function(w, h){
11790 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
11791 // if(typeof w == 'number'){
11792 // var x = w - this.trigger.getWidth();
11793 // this.inputEl().setWidth(this.adjustWidth('input', x));
11794 // this.trigger.setStyle('left', x+'px');
11799 adjustSize : Roo.BoxComponent.prototype.adjustSize,
11802 getResizeEl : function(){
11803 return this.inputEl();
11807 getPositionEl : function(){
11808 return this.inputEl();
11812 alignErrorIcon : function(){
11813 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
11817 initEvents : function(){
11821 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
11822 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
11823 if(!this.multiple && this.showToggleBtn){
11824 this.trigger = this.el.select('span.dropdown-toggle',true).first();
11825 if(this.hideTrigger){
11826 this.trigger.setDisplayed(false);
11828 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
11832 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
11835 if(this.removable && !this.editable && !this.tickable){
11836 var close = this.closeTriggerEl();
11839 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
11840 close.on('click', this.removeBtnClick, this, close);
11844 //this.trigger.addClassOnOver('x-form-trigger-over');
11845 //this.trigger.addClassOnClick('x-form-trigger-click');
11848 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
11852 closeTriggerEl : function()
11854 var close = this.el.select('.roo-combo-removable-btn', true).first();
11855 return close ? close : false;
11858 removeBtnClick : function(e, h, el)
11860 e.preventDefault();
11862 if(this.fireEvent("remove", this) !== false){
11864 this.fireEvent("afterremove", this)
11868 createList : function()
11870 this.list = Roo.get(document.body).createChild({
11871 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
11872 cls: 'typeahead typeahead-long dropdown-menu',
11873 style: 'display:none'
11876 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
11881 initTrigger : function(){
11886 onDestroy : function(){
11888 this.trigger.removeAllListeners();
11889 // this.trigger.remove();
11892 // this.wrap.remove();
11894 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
11898 onFocus : function(){
11899 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
11901 if(!this.mimicing){
11902 this.wrap.addClass('x-trigger-wrap-focus');
11903 this.mimicing = true;
11904 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
11905 if(this.monitorTab){
11906 this.el.on("keydown", this.checkTab, this);
11913 checkTab : function(e){
11914 if(e.getKey() == e.TAB){
11915 this.triggerBlur();
11920 onBlur : function(){
11925 mimicBlur : function(e, t){
11927 if(!this.wrap.contains(t) && this.validateBlur()){
11928 this.triggerBlur();
11934 triggerBlur : function(){
11935 this.mimicing = false;
11936 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
11937 if(this.monitorTab){
11938 this.el.un("keydown", this.checkTab, this);
11940 //this.wrap.removeClass('x-trigger-wrap-focus');
11941 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11945 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11946 validateBlur : function(e, t){
11951 onDisable : function(){
11952 this.inputEl().dom.disabled = true;
11953 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11955 // this.wrap.addClass('x-item-disabled');
11960 onEnable : function(){
11961 this.inputEl().dom.disabled = false;
11962 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11964 // this.el.removeClass('x-item-disabled');
11969 onShow : function(){
11970 var ae = this.getActionEl();
11973 ae.dom.style.display = '';
11974 ae.dom.style.visibility = 'visible';
11980 onHide : function(){
11981 var ae = this.getActionEl();
11982 ae.dom.style.display = 'none';
11986 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11987 * by an implementing function.
11989 * @param {EventObject} e
11991 onTriggerClick : Roo.emptyFn
11995 * Ext JS Library 1.1.1
11996 * Copyright(c) 2006-2007, Ext JS, LLC.
11998 * Originally Released Under LGPL - original licence link has changed is not relivant.
12001 * <script type="text/javascript">
12006 * @class Roo.data.SortTypes
12008 * Defines the default sorting (casting?) comparison functions used when sorting data.
12010 Roo.data.SortTypes = {
12012 * Default sort that does nothing
12013 * @param {Mixed} s The value being converted
12014 * @return {Mixed} The comparison value
12016 none : function(s){
12021 * The regular expression used to strip tags
12025 stripTagsRE : /<\/?[^>]+>/gi,
12028 * Strips all HTML tags to sort on text only
12029 * @param {Mixed} s The value being converted
12030 * @return {String} The comparison value
12032 asText : function(s){
12033 return String(s).replace(this.stripTagsRE, "");
12037 * Strips all HTML tags to sort on text only - Case insensitive
12038 * @param {Mixed} s The value being converted
12039 * @return {String} The comparison value
12041 asUCText : function(s){
12042 return String(s).toUpperCase().replace(this.stripTagsRE, "");
12046 * Case insensitive string
12047 * @param {Mixed} s The value being converted
12048 * @return {String} The comparison value
12050 asUCString : function(s) {
12051 return String(s).toUpperCase();
12056 * @param {Mixed} s The value being converted
12057 * @return {Number} The comparison value
12059 asDate : function(s) {
12063 if(s instanceof Date){
12064 return s.getTime();
12066 return Date.parse(String(s));
12071 * @param {Mixed} s The value being converted
12072 * @return {Float} The comparison value
12074 asFloat : function(s) {
12075 var val = parseFloat(String(s).replace(/,/g, ""));
12084 * @param {Mixed} s The value being converted
12085 * @return {Number} The comparison value
12087 asInt : function(s) {
12088 var val = parseInt(String(s).replace(/,/g, ""));
12096 * Ext JS Library 1.1.1
12097 * Copyright(c) 2006-2007, Ext JS, LLC.
12099 * Originally Released Under LGPL - original licence link has changed is not relivant.
12102 * <script type="text/javascript">
12106 * @class Roo.data.Record
12107 * Instances of this class encapsulate both record <em>definition</em> information, and record
12108 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
12109 * to access Records cached in an {@link Roo.data.Store} object.<br>
12111 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
12112 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
12115 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
12117 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
12118 * {@link #create}. The parameters are the same.
12119 * @param {Array} data An associative Array of data values keyed by the field name.
12120 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
12121 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
12122 * not specified an integer id is generated.
12124 Roo.data.Record = function(data, id){
12125 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
12130 * Generate a constructor for a specific record layout.
12131 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
12132 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
12133 * Each field definition object may contain the following properties: <ul>
12134 * <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,
12135 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
12136 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
12137 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
12138 * is being used, then this is a string containing the javascript expression to reference the data relative to
12139 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
12140 * to the data item relative to the record element. If the mapping expression is the same as the field name,
12141 * this may be omitted.</p></li>
12142 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
12143 * <ul><li>auto (Default, implies no conversion)</li>
12148 * <li>date</li></ul></p></li>
12149 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
12150 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
12151 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
12152 * by the Reader into an object that will be stored in the Record. It is passed the
12153 * following parameters:<ul>
12154 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
12156 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
12158 * <br>usage:<br><pre><code>
12159 var TopicRecord = Roo.data.Record.create(
12160 {name: 'title', mapping: 'topic_title'},
12161 {name: 'author', mapping: 'username'},
12162 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
12163 {name: 'lastPost', mapping: 'post_time', type: 'date'},
12164 {name: 'lastPoster', mapping: 'user2'},
12165 {name: 'excerpt', mapping: 'post_text'}
12168 var myNewRecord = new TopicRecord({
12169 title: 'Do my job please',
12172 lastPost: new Date(),
12173 lastPoster: 'Animal',
12174 excerpt: 'No way dude!'
12176 myStore.add(myNewRecord);
12181 Roo.data.Record.create = function(o){
12182 var f = function(){
12183 f.superclass.constructor.apply(this, arguments);
12185 Roo.extend(f, Roo.data.Record);
12186 var p = f.prototype;
12187 p.fields = new Roo.util.MixedCollection(false, function(field){
12190 for(var i = 0, len = o.length; i < len; i++){
12191 p.fields.add(new Roo.data.Field(o[i]));
12193 f.getField = function(name){
12194 return p.fields.get(name);
12199 Roo.data.Record.AUTO_ID = 1000;
12200 Roo.data.Record.EDIT = 'edit';
12201 Roo.data.Record.REJECT = 'reject';
12202 Roo.data.Record.COMMIT = 'commit';
12204 Roo.data.Record.prototype = {
12206 * Readonly flag - true if this record has been modified.
12215 join : function(store){
12216 this.store = store;
12220 * Set the named field to the specified value.
12221 * @param {String} name The name of the field to set.
12222 * @param {Object} value The value to set the field to.
12224 set : function(name, value){
12225 if(this.data[name] == value){
12229 if(!this.modified){
12230 this.modified = {};
12232 if(typeof this.modified[name] == 'undefined'){
12233 this.modified[name] = this.data[name];
12235 this.data[name] = value;
12236 if(!this.editing && this.store){
12237 this.store.afterEdit(this);
12242 * Get the value of the named field.
12243 * @param {String} name The name of the field to get the value of.
12244 * @return {Object} The value of the field.
12246 get : function(name){
12247 return this.data[name];
12251 beginEdit : function(){
12252 this.editing = true;
12253 this.modified = {};
12257 cancelEdit : function(){
12258 this.editing = false;
12259 delete this.modified;
12263 endEdit : function(){
12264 this.editing = false;
12265 if(this.dirty && this.store){
12266 this.store.afterEdit(this);
12271 * Usually called by the {@link Roo.data.Store} which owns the Record.
12272 * Rejects all changes made to the Record since either creation, or the last commit operation.
12273 * Modified fields are reverted to their original values.
12275 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12276 * of reject operations.
12278 reject : function(){
12279 var m = this.modified;
12281 if(typeof m[n] != "function"){
12282 this.data[n] = m[n];
12285 this.dirty = false;
12286 delete this.modified;
12287 this.editing = false;
12289 this.store.afterReject(this);
12294 * Usually called by the {@link Roo.data.Store} which owns the Record.
12295 * Commits all changes made to the Record since either creation, or the last commit operation.
12297 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12298 * of commit operations.
12300 commit : function(){
12301 this.dirty = false;
12302 delete this.modified;
12303 this.editing = false;
12305 this.store.afterCommit(this);
12310 hasError : function(){
12311 return this.error != null;
12315 clearError : function(){
12320 * Creates a copy of this record.
12321 * @param {String} id (optional) A new record id if you don't want to use this record's id
12324 copy : function(newId) {
12325 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
12329 * Ext JS Library 1.1.1
12330 * Copyright(c) 2006-2007, Ext JS, LLC.
12332 * Originally Released Under LGPL - original licence link has changed is not relivant.
12335 * <script type="text/javascript">
12341 * @class Roo.data.Store
12342 * @extends Roo.util.Observable
12343 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
12344 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
12346 * 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
12347 * has no knowledge of the format of the data returned by the Proxy.<br>
12349 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
12350 * instances from the data object. These records are cached and made available through accessor functions.
12352 * Creates a new Store.
12353 * @param {Object} config A config object containing the objects needed for the Store to access data,
12354 * and read the data into Records.
12356 Roo.data.Store = function(config){
12357 this.data = new Roo.util.MixedCollection(false);
12358 this.data.getKey = function(o){
12361 this.baseParams = {};
12363 this.paramNames = {
12368 "multisort" : "_multisort"
12371 if(config && config.data){
12372 this.inlineData = config.data;
12373 delete config.data;
12376 Roo.apply(this, config);
12378 if(this.reader){ // reader passed
12379 this.reader = Roo.factory(this.reader, Roo.data);
12380 this.reader.xmodule = this.xmodule || false;
12381 if(!this.recordType){
12382 this.recordType = this.reader.recordType;
12384 if(this.reader.onMetaChange){
12385 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
12389 if(this.recordType){
12390 this.fields = this.recordType.prototype.fields;
12392 this.modified = [];
12396 * @event datachanged
12397 * Fires when the data cache has changed, and a widget which is using this Store
12398 * as a Record cache should refresh its view.
12399 * @param {Store} this
12401 datachanged : true,
12403 * @event metachange
12404 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
12405 * @param {Store} this
12406 * @param {Object} meta The JSON metadata
12411 * Fires when Records have been added to the Store
12412 * @param {Store} this
12413 * @param {Roo.data.Record[]} records The array of Records added
12414 * @param {Number} index The index at which the record(s) were added
12419 * Fires when a Record has been removed from the Store
12420 * @param {Store} this
12421 * @param {Roo.data.Record} record The Record that was removed
12422 * @param {Number} index The index at which the record was removed
12427 * Fires when a Record has been updated
12428 * @param {Store} this
12429 * @param {Roo.data.Record} record The Record that was updated
12430 * @param {String} operation The update operation being performed. Value may be one of:
12432 Roo.data.Record.EDIT
12433 Roo.data.Record.REJECT
12434 Roo.data.Record.COMMIT
12440 * Fires when the data cache has been cleared.
12441 * @param {Store} this
12445 * @event beforeload
12446 * Fires before a request is made for a new data object. If the beforeload handler returns false
12447 * the load action will be canceled.
12448 * @param {Store} this
12449 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12453 * @event beforeloadadd
12454 * Fires after a new set of Records has been loaded.
12455 * @param {Store} this
12456 * @param {Roo.data.Record[]} records The Records that were loaded
12457 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12459 beforeloadadd : true,
12462 * Fires after a new set of Records has been loaded, before they are added to the store.
12463 * @param {Store} this
12464 * @param {Roo.data.Record[]} records The Records that were loaded
12465 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12466 * @params {Object} return from reader
12470 * @event loadexception
12471 * Fires if an exception occurs in the Proxy during loading.
12472 * Called with the signature of the Proxy's "loadexception" event.
12473 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
12476 * @param {Object} return from JsonData.reader() - success, totalRecords, records
12477 * @param {Object} load options
12478 * @param {Object} jsonData from your request (normally this contains the Exception)
12480 loadexception : true
12484 this.proxy = Roo.factory(this.proxy, Roo.data);
12485 this.proxy.xmodule = this.xmodule || false;
12486 this.relayEvents(this.proxy, ["loadexception"]);
12488 this.sortToggle = {};
12489 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
12491 Roo.data.Store.superclass.constructor.call(this);
12493 if(this.inlineData){
12494 this.loadData(this.inlineData);
12495 delete this.inlineData;
12499 Roo.extend(Roo.data.Store, Roo.util.Observable, {
12501 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
12502 * without a remote query - used by combo/forms at present.
12506 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
12509 * @cfg {Array} data Inline data to be loaded when the store is initialized.
12512 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
12513 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
12516 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
12517 * on any HTTP request
12520 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
12523 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
12527 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
12528 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
12530 remoteSort : false,
12533 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
12534 * loaded or when a record is removed. (defaults to false).
12536 pruneModifiedRecords : false,
12539 lastOptions : null,
12542 * Add Records to the Store and fires the add event.
12543 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
12545 add : function(records){
12546 records = [].concat(records);
12547 for(var i = 0, len = records.length; i < len; i++){
12548 records[i].join(this);
12550 var index = this.data.length;
12551 this.data.addAll(records);
12552 this.fireEvent("add", this, records, index);
12556 * Remove a Record from the Store and fires the remove event.
12557 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
12559 remove : function(record){
12560 var index = this.data.indexOf(record);
12561 this.data.removeAt(index);
12563 if(this.pruneModifiedRecords){
12564 this.modified.remove(record);
12566 this.fireEvent("remove", this, record, index);
12570 * Remove all Records from the Store and fires the clear event.
12572 removeAll : function(){
12574 if(this.pruneModifiedRecords){
12575 this.modified = [];
12577 this.fireEvent("clear", this);
12581 * Inserts Records to the Store at the given index and fires the add event.
12582 * @param {Number} index The start index at which to insert the passed Records.
12583 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
12585 insert : function(index, records){
12586 records = [].concat(records);
12587 for(var i = 0, len = records.length; i < len; i++){
12588 this.data.insert(index, records[i]);
12589 records[i].join(this);
12591 this.fireEvent("add", this, records, index);
12595 * Get the index within the cache of the passed Record.
12596 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
12597 * @return {Number} The index of the passed Record. Returns -1 if not found.
12599 indexOf : function(record){
12600 return this.data.indexOf(record);
12604 * Get the index within the cache of the Record with the passed id.
12605 * @param {String} id The id of the Record to find.
12606 * @return {Number} The index of the Record. Returns -1 if not found.
12608 indexOfId : function(id){
12609 return this.data.indexOfKey(id);
12613 * Get the Record with the specified id.
12614 * @param {String} id The id of the Record to find.
12615 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
12617 getById : function(id){
12618 return this.data.key(id);
12622 * Get the Record at the specified index.
12623 * @param {Number} index The index of the Record to find.
12624 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
12626 getAt : function(index){
12627 return this.data.itemAt(index);
12631 * Returns a range of Records between specified indices.
12632 * @param {Number} startIndex (optional) The starting index (defaults to 0)
12633 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
12634 * @return {Roo.data.Record[]} An array of Records
12636 getRange : function(start, end){
12637 return this.data.getRange(start, end);
12641 storeOptions : function(o){
12642 o = Roo.apply({}, o);
12645 this.lastOptions = o;
12649 * Loads the Record cache from the configured Proxy using the configured Reader.
12651 * If using remote paging, then the first load call must specify the <em>start</em>
12652 * and <em>limit</em> properties in the options.params property to establish the initial
12653 * position within the dataset, and the number of Records to cache on each read from the Proxy.
12655 * <strong>It is important to note that for remote data sources, loading is asynchronous,
12656 * and this call will return before the new data has been loaded. Perform any post-processing
12657 * in a callback function, or in a "load" event handler.</strong>
12659 * @param {Object} options An object containing properties which control loading options:<ul>
12660 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
12661 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
12662 * passed the following arguments:<ul>
12663 * <li>r : Roo.data.Record[]</li>
12664 * <li>options: Options object from the load call</li>
12665 * <li>success: Boolean success indicator</li></ul></li>
12666 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
12667 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
12670 load : function(options){
12671 options = options || {};
12672 if(this.fireEvent("beforeload", this, options) !== false){
12673 this.storeOptions(options);
12674 var p = Roo.apply(options.params || {}, this.baseParams);
12675 // if meta was not loaded from remote source.. try requesting it.
12676 if (!this.reader.metaFromRemote) {
12677 p._requestMeta = 1;
12679 if(this.sortInfo && this.remoteSort){
12680 var pn = this.paramNames;
12681 p[pn["sort"]] = this.sortInfo.field;
12682 p[pn["dir"]] = this.sortInfo.direction;
12684 if (this.multiSort) {
12685 var pn = this.paramNames;
12686 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
12689 this.proxy.load(p, this.reader, this.loadRecords, this, options);
12694 * Reloads the Record cache from the configured Proxy using the configured Reader and
12695 * the options from the last load operation performed.
12696 * @param {Object} options (optional) An object containing properties which may override the options
12697 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
12698 * the most recently used options are reused).
12700 reload : function(options){
12701 this.load(Roo.applyIf(options||{}, this.lastOptions));
12705 // Called as a callback by the Reader during a load operation.
12706 loadRecords : function(o, options, success){
12707 if(!o || success === false){
12708 if(success !== false){
12709 this.fireEvent("load", this, [], options, o);
12711 if(options.callback){
12712 options.callback.call(options.scope || this, [], options, false);
12716 // if data returned failure - throw an exception.
12717 if (o.success === false) {
12718 // show a message if no listener is registered.
12719 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
12720 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
12722 // loadmask wil be hooked into this..
12723 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
12726 var r = o.records, t = o.totalRecords || r.length;
12728 this.fireEvent("beforeloadadd", this, r, options, o);
12730 if(!options || options.add !== true){
12731 if(this.pruneModifiedRecords){
12732 this.modified = [];
12734 for(var i = 0, len = r.length; i < len; i++){
12738 this.data = this.snapshot;
12739 delete this.snapshot;
12742 this.data.addAll(r);
12743 this.totalLength = t;
12745 this.fireEvent("datachanged", this);
12747 this.totalLength = Math.max(t, this.data.length+r.length);
12751 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
12753 var e = new Roo.data.Record({});
12755 e.set(this.parent.displayField, this.parent.emptyTitle);
12756 e.set(this.parent.valueField, '');
12761 this.fireEvent("load", this, r, options, o);
12762 if(options.callback){
12763 options.callback.call(options.scope || this, r, options, true);
12769 * Loads data from a passed data block. A Reader which understands the format of the data
12770 * must have been configured in the constructor.
12771 * @param {Object} data The data block from which to read the Records. The format of the data expected
12772 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
12773 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
12775 loadData : function(o, append){
12776 var r = this.reader.readRecords(o);
12777 this.loadRecords(r, {add: append}, true);
12781 * using 'cn' the nested child reader read the child array into it's child stores.
12782 * @param {Object} rec The record with a 'children array
12784 loadDataFromChildren : function(rec)
12786 this.loadData(this.reader.toLoadData(rec));
12791 * Gets the number of cached records.
12793 * <em>If using paging, this may not be the total size of the dataset. If the data object
12794 * used by the Reader contains the dataset size, then the getTotalCount() function returns
12795 * the data set size</em>
12797 getCount : function(){
12798 return this.data.length || 0;
12802 * Gets the total number of records in the dataset as returned by the server.
12804 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
12805 * the dataset size</em>
12807 getTotalCount : function(){
12808 return this.totalLength || 0;
12812 * Returns the sort state of the Store as an object with two properties:
12814 field {String} The name of the field by which the Records are sorted
12815 direction {String} The sort order, "ASC" or "DESC"
12818 getSortState : function(){
12819 return this.sortInfo;
12823 applySort : function(){
12824 if(this.sortInfo && !this.remoteSort){
12825 var s = this.sortInfo, f = s.field;
12826 var st = this.fields.get(f).sortType;
12827 var fn = function(r1, r2){
12828 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
12829 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
12831 this.data.sort(s.direction, fn);
12832 if(this.snapshot && this.snapshot != this.data){
12833 this.snapshot.sort(s.direction, fn);
12839 * Sets the default sort column and order to be used by the next load operation.
12840 * @param {String} fieldName The name of the field to sort by.
12841 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
12843 setDefaultSort : function(field, dir){
12844 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
12848 * Sort the Records.
12849 * If remote sorting is used, the sort is performed on the server, and the cache is
12850 * reloaded. If local sorting is used, the cache is sorted internally.
12851 * @param {String} fieldName The name of the field to sort by.
12852 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
12854 sort : function(fieldName, dir){
12855 var f = this.fields.get(fieldName);
12857 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
12859 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
12860 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
12865 this.sortToggle[f.name] = dir;
12866 this.sortInfo = {field: f.name, direction: dir};
12867 if(!this.remoteSort){
12869 this.fireEvent("datachanged", this);
12871 this.load(this.lastOptions);
12876 * Calls the specified function for each of the Records in the cache.
12877 * @param {Function} fn The function to call. The Record is passed as the first parameter.
12878 * Returning <em>false</em> aborts and exits the iteration.
12879 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
12881 each : function(fn, scope){
12882 this.data.each(fn, scope);
12886 * Gets all records modified since the last commit. Modified records are persisted across load operations
12887 * (e.g., during paging).
12888 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
12890 getModifiedRecords : function(){
12891 return this.modified;
12895 createFilterFn : function(property, value, anyMatch){
12896 if(!value.exec){ // not a regex
12897 value = String(value);
12898 if(value.length == 0){
12901 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
12903 return function(r){
12904 return value.test(r.data[property]);
12909 * Sums the value of <i>property</i> for each record between start and end and returns the result.
12910 * @param {String} property A field on your records
12911 * @param {Number} start The record index to start at (defaults to 0)
12912 * @param {Number} end The last record index to include (defaults to length - 1)
12913 * @return {Number} The sum
12915 sum : function(property, start, end){
12916 var rs = this.data.items, v = 0;
12917 start = start || 0;
12918 end = (end || end === 0) ? end : rs.length-1;
12920 for(var i = start; i <= end; i++){
12921 v += (rs[i].data[property] || 0);
12927 * Filter the records by a specified property.
12928 * @param {String} field A field on your records
12929 * @param {String/RegExp} value Either a string that the field
12930 * should start with or a RegExp to test against the field
12931 * @param {Boolean} anyMatch True to match any part not just the beginning
12933 filter : function(property, value, anyMatch){
12934 var fn = this.createFilterFn(property, value, anyMatch);
12935 return fn ? this.filterBy(fn) : this.clearFilter();
12939 * Filter by a function. The specified function will be called with each
12940 * record in this data source. If the function returns true the record is included,
12941 * otherwise it is filtered.
12942 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12943 * @param {Object} scope (optional) The scope of the function (defaults to this)
12945 filterBy : function(fn, scope){
12946 this.snapshot = this.snapshot || this.data;
12947 this.data = this.queryBy(fn, scope||this);
12948 this.fireEvent("datachanged", this);
12952 * Query the records by a specified property.
12953 * @param {String} field A field on your records
12954 * @param {String/RegExp} value Either a string that the field
12955 * should start with or a RegExp to test against the field
12956 * @param {Boolean} anyMatch True to match any part not just the beginning
12957 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12959 query : function(property, value, anyMatch){
12960 var fn = this.createFilterFn(property, value, anyMatch);
12961 return fn ? this.queryBy(fn) : this.data.clone();
12965 * Query by a function. The specified function will be called with each
12966 * record in this data source. If the function returns true the record is included
12968 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12969 * @param {Object} scope (optional) The scope of the function (defaults to this)
12970 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12972 queryBy : function(fn, scope){
12973 var data = this.snapshot || this.data;
12974 return data.filterBy(fn, scope||this);
12978 * Collects unique values for a particular dataIndex from this store.
12979 * @param {String} dataIndex The property to collect
12980 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12981 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12982 * @return {Array} An array of the unique values
12984 collect : function(dataIndex, allowNull, bypassFilter){
12985 var d = (bypassFilter === true && this.snapshot) ?
12986 this.snapshot.items : this.data.items;
12987 var v, sv, r = [], l = {};
12988 for(var i = 0, len = d.length; i < len; i++){
12989 v = d[i].data[dataIndex];
12991 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
13000 * Revert to a view of the Record cache with no filtering applied.
13001 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
13003 clearFilter : function(suppressEvent){
13004 if(this.snapshot && this.snapshot != this.data){
13005 this.data = this.snapshot;
13006 delete this.snapshot;
13007 if(suppressEvent !== true){
13008 this.fireEvent("datachanged", this);
13014 afterEdit : function(record){
13015 if(this.modified.indexOf(record) == -1){
13016 this.modified.push(record);
13018 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
13022 afterReject : function(record){
13023 this.modified.remove(record);
13024 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
13028 afterCommit : function(record){
13029 this.modified.remove(record);
13030 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
13034 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
13035 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
13037 commitChanges : function(){
13038 var m = this.modified.slice(0);
13039 this.modified = [];
13040 for(var i = 0, len = m.length; i < len; i++){
13046 * Cancel outstanding changes on all changed records.
13048 rejectChanges : function(){
13049 var m = this.modified.slice(0);
13050 this.modified = [];
13051 for(var i = 0, len = m.length; i < len; i++){
13056 onMetaChange : function(meta, rtype, o){
13057 this.recordType = rtype;
13058 this.fields = rtype.prototype.fields;
13059 delete this.snapshot;
13060 this.sortInfo = meta.sortInfo || this.sortInfo;
13061 this.modified = [];
13062 this.fireEvent('metachange', this, this.reader.meta);
13065 moveIndex : function(data, type)
13067 var index = this.indexOf(data);
13069 var newIndex = index + type;
13073 this.insert(newIndex, data);
13078 * Ext JS Library 1.1.1
13079 * Copyright(c) 2006-2007, Ext JS, LLC.
13081 * Originally Released Under LGPL - original licence link has changed is not relivant.
13084 * <script type="text/javascript">
13088 * @class Roo.data.SimpleStore
13089 * @extends Roo.data.Store
13090 * Small helper class to make creating Stores from Array data easier.
13091 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
13092 * @cfg {Array} fields An array of field definition objects, or field name strings.
13093 * @cfg {Object} an existing reader (eg. copied from another store)
13094 * @cfg {Array} data The multi-dimensional array of data
13096 * @param {Object} config
13098 Roo.data.SimpleStore = function(config)
13100 Roo.data.SimpleStore.superclass.constructor.call(this, {
13102 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
13105 Roo.data.Record.create(config.fields)
13107 proxy : new Roo.data.MemoryProxy(config.data)
13111 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
13113 * Ext JS Library 1.1.1
13114 * Copyright(c) 2006-2007, Ext JS, LLC.
13116 * Originally Released Under LGPL - original licence link has changed is not relivant.
13119 * <script type="text/javascript">
13124 * @extends Roo.data.Store
13125 * @class Roo.data.JsonStore
13126 * Small helper class to make creating Stores for JSON data easier. <br/>
13128 var store = new Roo.data.JsonStore({
13129 url: 'get-images.php',
13131 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
13134 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
13135 * JsonReader and HttpProxy (unless inline data is provided).</b>
13136 * @cfg {Array} fields An array of field definition objects, or field name strings.
13138 * @param {Object} config
13140 Roo.data.JsonStore = function(c){
13141 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
13142 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
13143 reader: new Roo.data.JsonReader(c, c.fields)
13146 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
13148 * Ext JS Library 1.1.1
13149 * Copyright(c) 2006-2007, Ext JS, LLC.
13151 * Originally Released Under LGPL - original licence link has changed is not relivant.
13154 * <script type="text/javascript">
13158 Roo.data.Field = function(config){
13159 if(typeof config == "string"){
13160 config = {name: config};
13162 Roo.apply(this, config);
13165 this.type = "auto";
13168 var st = Roo.data.SortTypes;
13169 // named sortTypes are supported, here we look them up
13170 if(typeof this.sortType == "string"){
13171 this.sortType = st[this.sortType];
13174 // set default sortType for strings and dates
13175 if(!this.sortType){
13178 this.sortType = st.asUCString;
13181 this.sortType = st.asDate;
13184 this.sortType = st.none;
13189 var stripRe = /[\$,%]/g;
13191 // prebuilt conversion function for this field, instead of
13192 // switching every time we're reading a value
13194 var cv, dateFormat = this.dateFormat;
13199 cv = function(v){ return v; };
13202 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
13206 return v !== undefined && v !== null && v !== '' ?
13207 parseInt(String(v).replace(stripRe, ""), 10) : '';
13212 return v !== undefined && v !== null && v !== '' ?
13213 parseFloat(String(v).replace(stripRe, ""), 10) : '';
13218 cv = function(v){ return v === true || v === "true" || v == 1; };
13225 if(v instanceof Date){
13229 if(dateFormat == "timestamp"){
13230 return new Date(v*1000);
13232 return Date.parseDate(v, dateFormat);
13234 var parsed = Date.parse(v);
13235 return parsed ? new Date(parsed) : null;
13244 Roo.data.Field.prototype = {
13252 * Ext JS Library 1.1.1
13253 * Copyright(c) 2006-2007, Ext JS, LLC.
13255 * Originally Released Under LGPL - original licence link has changed is not relivant.
13258 * <script type="text/javascript">
13261 // Base class for reading structured data from a data source. This class is intended to be
13262 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
13265 * @class Roo.data.DataReader
13266 * Base class for reading structured data from a data source. This class is intended to be
13267 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
13270 Roo.data.DataReader = function(meta, recordType){
13274 this.recordType = recordType instanceof Array ?
13275 Roo.data.Record.create(recordType) : recordType;
13278 Roo.data.DataReader.prototype = {
13281 readerType : 'Data',
13283 * Create an empty record
13284 * @param {Object} data (optional) - overlay some values
13285 * @return {Roo.data.Record} record created.
13287 newRow : function(d) {
13289 this.recordType.prototype.fields.each(function(c) {
13291 case 'int' : da[c.name] = 0; break;
13292 case 'date' : da[c.name] = new Date(); break;
13293 case 'float' : da[c.name] = 0.0; break;
13294 case 'boolean' : da[c.name] = false; break;
13295 default : da[c.name] = ""; break;
13299 return new this.recordType(Roo.apply(da, d));
13305 * Ext JS Library 1.1.1
13306 * Copyright(c) 2006-2007, Ext JS, LLC.
13308 * Originally Released Under LGPL - original licence link has changed is not relivant.
13311 * <script type="text/javascript">
13315 * @class Roo.data.DataProxy
13316 * @extends Roo.data.Observable
13317 * This class is an abstract base class for implementations which provide retrieval of
13318 * unformatted data objects.<br>
13320 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
13321 * (of the appropriate type which knows how to parse the data object) to provide a block of
13322 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
13324 * Custom implementations must implement the load method as described in
13325 * {@link Roo.data.HttpProxy#load}.
13327 Roo.data.DataProxy = function(){
13330 * @event beforeload
13331 * Fires before a network request is made to retrieve a data object.
13332 * @param {Object} This DataProxy object.
13333 * @param {Object} params The params parameter to the load function.
13338 * Fires before the load method's callback is called.
13339 * @param {Object} This DataProxy object.
13340 * @param {Object} o The data object.
13341 * @param {Object} arg The callback argument object passed to the load function.
13345 * @event loadexception
13346 * Fires if an Exception occurs during data retrieval.
13347 * @param {Object} This DataProxy object.
13348 * @param {Object} o The data object.
13349 * @param {Object} arg The callback argument object passed to the load function.
13350 * @param {Object} e The Exception.
13352 loadexception : true
13354 Roo.data.DataProxy.superclass.constructor.call(this);
13357 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
13360 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
13364 * Ext JS Library 1.1.1
13365 * Copyright(c) 2006-2007, Ext JS, LLC.
13367 * Originally Released Under LGPL - original licence link has changed is not relivant.
13370 * <script type="text/javascript">
13373 * @class Roo.data.MemoryProxy
13374 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
13375 * to the Reader when its load method is called.
13377 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
13379 Roo.data.MemoryProxy = function(data){
13383 Roo.data.MemoryProxy.superclass.constructor.call(this);
13387 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
13390 * Load data from the requested source (in this case an in-memory
13391 * data object passed to the constructor), read the data object into
13392 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
13393 * process that block using the passed callback.
13394 * @param {Object} params This parameter is not used by the MemoryProxy class.
13395 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13396 * object into a block of Roo.data.Records.
13397 * @param {Function} callback The function into which to pass the block of Roo.data.records.
13398 * The function must be passed <ul>
13399 * <li>The Record block object</li>
13400 * <li>The "arg" argument from the load function</li>
13401 * <li>A boolean success indicator</li>
13403 * @param {Object} scope The scope in which to call the callback
13404 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13406 load : function(params, reader, callback, scope, arg){
13407 params = params || {};
13410 result = reader.readRecords(params.data ? params.data :this.data);
13412 this.fireEvent("loadexception", this, arg, null, e);
13413 callback.call(scope, null, arg, false);
13416 callback.call(scope, result, arg, true);
13420 update : function(params, records){
13425 * Ext JS Library 1.1.1
13426 * Copyright(c) 2006-2007, Ext JS, LLC.
13428 * Originally Released Under LGPL - original licence link has changed is not relivant.
13431 * <script type="text/javascript">
13434 * @class Roo.data.HttpProxy
13435 * @extends Roo.data.DataProxy
13436 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
13437 * configured to reference a certain URL.<br><br>
13439 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
13440 * from which the running page was served.<br><br>
13442 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
13444 * Be aware that to enable the browser to parse an XML document, the server must set
13445 * the Content-Type header in the HTTP response to "text/xml".
13447 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
13448 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
13449 * will be used to make the request.
13451 Roo.data.HttpProxy = function(conn){
13452 Roo.data.HttpProxy.superclass.constructor.call(this);
13453 // is conn a conn config or a real conn?
13455 this.useAjax = !conn || !conn.events;
13459 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
13460 // thse are take from connection...
13463 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
13466 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
13467 * extra parameters to each request made by this object. (defaults to undefined)
13470 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
13471 * to each request made by this object. (defaults to undefined)
13474 * @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)
13477 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13480 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
13486 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13490 * Return the {@link Roo.data.Connection} object being used by this Proxy.
13491 * @return {Connection} The Connection object. This object may be used to subscribe to events on
13492 * a finer-grained basis than the DataProxy events.
13494 getConnection : function(){
13495 return this.useAjax ? Roo.Ajax : this.conn;
13499 * Load data from the configured {@link Roo.data.Connection}, read the data object into
13500 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
13501 * process that block using the passed callback.
13502 * @param {Object} params An object containing properties which are to be used as HTTP parameters
13503 * for the request to the remote server.
13504 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13505 * object into a block of Roo.data.Records.
13506 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
13507 * The function must be passed <ul>
13508 * <li>The Record block object</li>
13509 * <li>The "arg" argument from the load function</li>
13510 * <li>A boolean success indicator</li>
13512 * @param {Object} scope The scope in which to call the callback
13513 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13515 load : function(params, reader, callback, scope, arg){
13516 if(this.fireEvent("beforeload", this, params) !== false){
13518 params : params || {},
13520 callback : callback,
13525 callback : this.loadResponse,
13529 Roo.applyIf(o, this.conn);
13530 if(this.activeRequest){
13531 Roo.Ajax.abort(this.activeRequest);
13533 this.activeRequest = Roo.Ajax.request(o);
13535 this.conn.request(o);
13538 callback.call(scope||this, null, arg, false);
13543 loadResponse : function(o, success, response){
13544 delete this.activeRequest;
13546 this.fireEvent("loadexception", this, o, response);
13547 o.request.callback.call(o.request.scope, null, o.request.arg, false);
13552 result = o.reader.read(response);
13554 this.fireEvent("loadexception", this, o, response, e);
13555 o.request.callback.call(o.request.scope, null, o.request.arg, false);
13559 this.fireEvent("load", this, o, o.request.arg);
13560 o.request.callback.call(o.request.scope, result, o.request.arg, true);
13564 update : function(dataSet){
13569 updateResponse : function(dataSet){
13574 * Ext JS Library 1.1.1
13575 * Copyright(c) 2006-2007, Ext JS, LLC.
13577 * Originally Released Under LGPL - original licence link has changed is not relivant.
13580 * <script type="text/javascript">
13584 * @class Roo.data.ScriptTagProxy
13585 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
13586 * other than the originating domain of the running page.<br><br>
13588 * <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
13589 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
13591 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
13592 * source code that is used as the source inside a <script> tag.<br><br>
13594 * In order for the browser to process the returned data, the server must wrap the data object
13595 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
13596 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
13597 * depending on whether the callback name was passed:
13600 boolean scriptTag = false;
13601 String cb = request.getParameter("callback");
13604 response.setContentType("text/javascript");
13606 response.setContentType("application/x-json");
13608 Writer out = response.getWriter();
13610 out.write(cb + "(");
13612 out.print(dataBlock.toJsonString());
13619 * @param {Object} config A configuration object.
13621 Roo.data.ScriptTagProxy = function(config){
13622 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
13623 Roo.apply(this, config);
13624 this.head = document.getElementsByTagName("head")[0];
13627 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
13629 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
13631 * @cfg {String} url The URL from which to request the data object.
13634 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
13638 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
13639 * the server the name of the callback function set up by the load call to process the returned data object.
13640 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
13641 * javascript output which calls this named function passing the data object as its only parameter.
13643 callbackParam : "callback",
13645 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
13646 * name to the request.
13651 * Load data from the configured URL, read the data object into
13652 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
13653 * process that block using the passed callback.
13654 * @param {Object} params An object containing properties which are to be used as HTTP parameters
13655 * for the request to the remote server.
13656 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13657 * object into a block of Roo.data.Records.
13658 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
13659 * The function must be passed <ul>
13660 * <li>The Record block object</li>
13661 * <li>The "arg" argument from the load function</li>
13662 * <li>A boolean success indicator</li>
13664 * @param {Object} scope The scope in which to call the callback
13665 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13667 load : function(params, reader, callback, scope, arg){
13668 if(this.fireEvent("beforeload", this, params) !== false){
13670 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
13672 var url = this.url;
13673 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
13675 url += "&_dc=" + (new Date().getTime());
13677 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
13680 cb : "stcCallback"+transId,
13681 scriptId : "stcScript"+transId,
13685 callback : callback,
13691 window[trans.cb] = function(o){
13692 conn.handleResponse(o, trans);
13695 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
13697 if(this.autoAbort !== false){
13701 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
13703 var script = document.createElement("script");
13704 script.setAttribute("src", url);
13705 script.setAttribute("type", "text/javascript");
13706 script.setAttribute("id", trans.scriptId);
13707 this.head.appendChild(script);
13709 this.trans = trans;
13711 callback.call(scope||this, null, arg, false);
13716 isLoading : function(){
13717 return this.trans ? true : false;
13721 * Abort the current server request.
13723 abort : function(){
13724 if(this.isLoading()){
13725 this.destroyTrans(this.trans);
13730 destroyTrans : function(trans, isLoaded){
13731 this.head.removeChild(document.getElementById(trans.scriptId));
13732 clearTimeout(trans.timeoutId);
13734 window[trans.cb] = undefined;
13736 delete window[trans.cb];
13739 // if hasn't been loaded, wait for load to remove it to prevent script error
13740 window[trans.cb] = function(){
13741 window[trans.cb] = undefined;
13743 delete window[trans.cb];
13750 handleResponse : function(o, trans){
13751 this.trans = false;
13752 this.destroyTrans(trans, true);
13755 result = trans.reader.readRecords(o);
13757 this.fireEvent("loadexception", this, o, trans.arg, e);
13758 trans.callback.call(trans.scope||window, null, trans.arg, false);
13761 this.fireEvent("load", this, o, trans.arg);
13762 trans.callback.call(trans.scope||window, result, trans.arg, true);
13766 handleFailure : function(trans){
13767 this.trans = false;
13768 this.destroyTrans(trans, false);
13769 this.fireEvent("loadexception", this, null, trans.arg);
13770 trans.callback.call(trans.scope||window, null, trans.arg, false);
13774 * Ext JS Library 1.1.1
13775 * Copyright(c) 2006-2007, Ext JS, LLC.
13777 * Originally Released Under LGPL - original licence link has changed is not relivant.
13780 * <script type="text/javascript">
13784 * @class Roo.data.JsonReader
13785 * @extends Roo.data.DataReader
13786 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
13787 * based on mappings in a provided Roo.data.Record constructor.
13789 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
13790 * in the reply previously.
13795 var RecordDef = Roo.data.Record.create([
13796 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
13797 {name: 'occupation'} // This field will use "occupation" as the mapping.
13799 var myReader = new Roo.data.JsonReader({
13800 totalProperty: "results", // The property which contains the total dataset size (optional)
13801 root: "rows", // The property which contains an Array of row objects
13802 id: "id" // The property within each row object that provides an ID for the record (optional)
13806 * This would consume a JSON file like this:
13808 { 'results': 2, 'rows': [
13809 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
13810 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
13813 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
13814 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
13815 * paged from the remote server.
13816 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
13817 * @cfg {String} root name of the property which contains the Array of row objects.
13818 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13819 * @cfg {Array} fields Array of field definition objects
13821 * Create a new JsonReader
13822 * @param {Object} meta Metadata configuration options
13823 * @param {Object} recordType Either an Array of field definition objects,
13824 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
13826 Roo.data.JsonReader = function(meta, recordType){
13829 // set some defaults:
13830 Roo.applyIf(meta, {
13831 totalProperty: 'total',
13832 successProperty : 'success',
13837 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13839 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
13841 readerType : 'Json',
13844 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
13845 * Used by Store query builder to append _requestMeta to params.
13848 metaFromRemote : false,
13850 * This method is only used by a DataProxy which has retrieved data from a remote server.
13851 * @param {Object} response The XHR object which contains the JSON data in its responseText.
13852 * @return {Object} data A data block which is used by an Roo.data.Store object as
13853 * a cache of Roo.data.Records.
13855 read : function(response){
13856 var json = response.responseText;
13858 var o = /* eval:var:o */ eval("("+json+")");
13860 throw {message: "JsonReader.read: Json object not found"};
13866 this.metaFromRemote = true;
13867 this.meta = o.metaData;
13868 this.recordType = Roo.data.Record.create(o.metaData.fields);
13869 this.onMetaChange(this.meta, this.recordType, o);
13871 return this.readRecords(o);
13874 // private function a store will implement
13875 onMetaChange : function(meta, recordType, o){
13882 simpleAccess: function(obj, subsc) {
13889 getJsonAccessor: function(){
13891 return function(expr) {
13893 return(re.test(expr))
13894 ? new Function("obj", "return obj." + expr)
13899 return Roo.emptyFn;
13904 * Create a data block containing Roo.data.Records from an XML document.
13905 * @param {Object} o An object which contains an Array of row objects in the property specified
13906 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
13907 * which contains the total size of the dataset.
13908 * @return {Object} data A data block which is used by an Roo.data.Store object as
13909 * a cache of Roo.data.Records.
13911 readRecords : function(o){
13913 * After any data loads, the raw JSON data is available for further custom processing.
13917 var s = this.meta, Record = this.recordType,
13918 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
13920 // Generate extraction functions for the totalProperty, the root, the id, and for each field
13922 if(s.totalProperty) {
13923 this.getTotal = this.getJsonAccessor(s.totalProperty);
13925 if(s.successProperty) {
13926 this.getSuccess = this.getJsonAccessor(s.successProperty);
13928 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
13930 var g = this.getJsonAccessor(s.id);
13931 this.getId = function(rec) {
13933 return (r === undefined || r === "") ? null : r;
13936 this.getId = function(){return null;};
13939 for(var jj = 0; jj < fl; jj++){
13941 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
13942 this.ef[jj] = this.getJsonAccessor(map);
13946 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
13947 if(s.totalProperty){
13948 var vt = parseInt(this.getTotal(o), 10);
13953 if(s.successProperty){
13954 var vs = this.getSuccess(o);
13955 if(vs === false || vs === 'false'){
13960 for(var i = 0; i < c; i++){
13963 var id = this.getId(n);
13964 for(var j = 0; j < fl; j++){
13966 var v = this.ef[j](n);
13968 Roo.log('missing convert for ' + f.name);
13972 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13974 var record = new Record(values, id);
13976 records[i] = record;
13982 totalRecords : totalRecords
13985 // used when loading children.. @see loadDataFromChildren
13986 toLoadData: function(rec)
13988 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
13989 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
13990 return { data : data, total : data.length };
13995 * Ext JS Library 1.1.1
13996 * Copyright(c) 2006-2007, Ext JS, LLC.
13998 * Originally Released Under LGPL - original licence link has changed is not relivant.
14001 * <script type="text/javascript">
14005 * @class Roo.data.ArrayReader
14006 * @extends Roo.data.DataReader
14007 * Data reader class to create an Array of Roo.data.Record objects from an Array.
14008 * Each element of that Array represents a row of data fields. The
14009 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
14010 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
14014 var RecordDef = Roo.data.Record.create([
14015 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
14016 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
14018 var myReader = new Roo.data.ArrayReader({
14019 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
14023 * This would consume an Array like this:
14025 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
14029 * Create a new JsonReader
14030 * @param {Object} meta Metadata configuration options.
14031 * @param {Object|Array} recordType Either an Array of field definition objects
14033 * @cfg {Array} fields Array of field definition objects
14034 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14035 * as specified to {@link Roo.data.Record#create},
14036 * or an {@link Roo.data.Record} object
14039 * created using {@link Roo.data.Record#create}.
14041 Roo.data.ArrayReader = function(meta, recordType)
14043 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14046 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
14049 * Create a data block containing Roo.data.Records from an XML document.
14050 * @param {Object} o An Array of row objects which represents the dataset.
14051 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
14052 * a cache of Roo.data.Records.
14054 readRecords : function(o)
14056 var sid = this.meta ? this.meta.id : null;
14057 var recordType = this.recordType, fields = recordType.prototype.fields;
14060 for(var i = 0; i < root.length; i++){
14063 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
14064 for(var j = 0, jlen = fields.length; j < jlen; j++){
14065 var f = fields.items[j];
14066 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
14067 var v = n[k] !== undefined ? n[k] : f.defaultValue;
14069 values[f.name] = v;
14071 var record = new recordType(values, id);
14073 records[records.length] = record;
14077 totalRecords : records.length
14080 // used when loading children.. @see loadDataFromChildren
14081 toLoadData: function(rec)
14083 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14084 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14095 * @class Roo.bootstrap.ComboBox
14096 * @extends Roo.bootstrap.TriggerField
14097 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
14098 * @cfg {Boolean} append (true|false) default false
14099 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
14100 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
14101 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
14102 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
14103 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
14104 * @cfg {Boolean} animate default true
14105 * @cfg {Boolean} emptyResultText only for touch device
14106 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
14107 * @cfg {String} emptyTitle default ''
14109 * Create a new ComboBox.
14110 * @param {Object} config Configuration options
14112 Roo.bootstrap.ComboBox = function(config){
14113 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
14117 * Fires when the dropdown list is expanded
14118 * @param {Roo.bootstrap.ComboBox} combo This combo box
14123 * Fires when the dropdown list is collapsed
14124 * @param {Roo.bootstrap.ComboBox} combo This combo box
14128 * @event beforeselect
14129 * Fires before a list item is selected. Return false to cancel the selection.
14130 * @param {Roo.bootstrap.ComboBox} combo This combo box
14131 * @param {Roo.data.Record} record The data record returned from the underlying store
14132 * @param {Number} index The index of the selected item in the dropdown list
14134 'beforeselect' : true,
14137 * Fires when a list item is selected
14138 * @param {Roo.bootstrap.ComboBox} combo This combo box
14139 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
14140 * @param {Number} index The index of the selected item in the dropdown list
14144 * @event beforequery
14145 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
14146 * The event object passed has these properties:
14147 * @param {Roo.bootstrap.ComboBox} combo This combo box
14148 * @param {String} query The query
14149 * @param {Boolean} forceAll true to force "all" query
14150 * @param {Boolean} cancel true to cancel the query
14151 * @param {Object} e The query event object
14153 'beforequery': true,
14156 * Fires when the 'add' icon is pressed (add a listener to enable add button)
14157 * @param {Roo.bootstrap.ComboBox} combo This combo box
14162 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
14163 * @param {Roo.bootstrap.ComboBox} combo This combo box
14164 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
14169 * Fires when the remove value from the combobox array
14170 * @param {Roo.bootstrap.ComboBox} combo This combo box
14174 * @event afterremove
14175 * Fires when the remove value from the combobox array
14176 * @param {Roo.bootstrap.ComboBox} combo This combo box
14178 'afterremove' : true,
14180 * @event specialfilter
14181 * Fires when specialfilter
14182 * @param {Roo.bootstrap.ComboBox} combo This combo box
14184 'specialfilter' : true,
14187 * Fires when tick the element
14188 * @param {Roo.bootstrap.ComboBox} combo This combo box
14192 * @event touchviewdisplay
14193 * Fires when touch view require special display (default is using displayField)
14194 * @param {Roo.bootstrap.ComboBox} combo This combo box
14195 * @param {Object} cfg set html .
14197 'touchviewdisplay' : true
14202 this.tickItems = [];
14204 this.selectedIndex = -1;
14205 if(this.mode == 'local'){
14206 if(config.queryDelay === undefined){
14207 this.queryDelay = 10;
14209 if(config.minChars === undefined){
14215 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
14218 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
14219 * rendering into an Roo.Editor, defaults to false)
14222 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
14223 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
14226 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
14229 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
14230 * the dropdown list (defaults to undefined, with no header element)
14234 * @cfg {String/Roo.Template} tpl The template to use to render the output
14238 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
14240 listWidth: undefined,
14242 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
14243 * mode = 'remote' or 'text' if mode = 'local')
14245 displayField: undefined,
14248 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
14249 * mode = 'remote' or 'value' if mode = 'local').
14250 * Note: use of a valueField requires the user make a selection
14251 * in order for a value to be mapped.
14253 valueField: undefined,
14255 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
14260 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
14261 * field's data value (defaults to the underlying DOM element's name)
14263 hiddenName: undefined,
14265 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
14269 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
14271 selectedClass: 'active',
14274 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14278 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
14279 * anchor positions (defaults to 'tl-bl')
14281 listAlign: 'tl-bl?',
14283 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
14287 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
14288 * query specified by the allQuery config option (defaults to 'query')
14290 triggerAction: 'query',
14292 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
14293 * (defaults to 4, does not apply if editable = false)
14297 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
14298 * delay (typeAheadDelay) if it matches a known value (defaults to false)
14302 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
14303 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
14307 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
14308 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
14312 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
14313 * when editable = true (defaults to false)
14315 selectOnFocus:false,
14317 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
14319 queryParam: 'query',
14321 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
14322 * when mode = 'remote' (defaults to 'Loading...')
14324 loadingText: 'Loading...',
14326 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
14330 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
14334 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
14335 * traditional select (defaults to true)
14339 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
14343 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
14347 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
14348 * listWidth has a higher value)
14352 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
14353 * allow the user to set arbitrary text into the field (defaults to false)
14355 forceSelection:false,
14357 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
14358 * if typeAhead = true (defaults to 250)
14360 typeAheadDelay : 250,
14362 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
14363 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
14365 valueNotFoundText : undefined,
14367 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
14369 blockFocus : false,
14372 * @cfg {Boolean} disableClear Disable showing of clear button.
14374 disableClear : false,
14376 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
14378 alwaysQuery : false,
14381 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
14386 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
14388 invalidClass : "has-warning",
14391 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
14393 validClass : "has-success",
14396 * @cfg {Boolean} specialFilter (true|false) special filter default false
14398 specialFilter : false,
14401 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
14403 mobileTouchView : true,
14406 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
14408 useNativeIOS : false,
14411 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
14413 mobile_restrict_height : false,
14415 ios_options : false,
14427 btnPosition : 'right',
14428 triggerList : true,
14429 showToggleBtn : true,
14431 emptyResultText: 'Empty',
14432 triggerText : 'Select',
14435 // element that contains real text value.. (when hidden is used..)
14437 getAutoCreate : function()
14442 * Render classic select for iso
14445 if(Roo.isIOS && this.useNativeIOS){
14446 cfg = this.getAutoCreateNativeIOS();
14454 if(Roo.isTouch && this.mobileTouchView){
14455 cfg = this.getAutoCreateTouchView();
14462 if(!this.tickable){
14463 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
14468 * ComboBox with tickable selections
14471 var align = this.labelAlign || this.parentLabelAlign();
14474 cls : 'form-group roo-combobox-tickable' //input-group
14477 var btn_text_select = '';
14478 var btn_text_done = '';
14479 var btn_text_cancel = '';
14481 if (this.btn_text_show) {
14482 btn_text_select = 'Select';
14483 btn_text_done = 'Done';
14484 btn_text_cancel = 'Cancel';
14489 cls : 'tickable-buttons',
14494 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
14495 //html : this.triggerText
14496 html: btn_text_select
14502 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
14504 html: btn_text_done
14510 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
14512 html: btn_text_cancel
14518 buttons.cn.unshift({
14520 cls: 'roo-select2-search-field-input'
14526 Roo.each(buttons.cn, function(c){
14528 c.cls += ' btn-' + _this.size;
14531 if (_this.disabled) {
14538 style : 'display: contents',
14543 cls: 'form-hidden-field'
14547 cls: 'roo-select2-choices',
14551 cls: 'roo-select2-search-field',
14562 cls: 'roo-select2-container input-group roo-select2-container-multi',
14568 // cls: 'typeahead typeahead-long dropdown-menu',
14569 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
14574 if(this.hasFeedback && !this.allowBlank){
14578 cls: 'glyphicon form-control-feedback'
14581 combobox.cn.push(feedback);
14586 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
14587 tooltip : 'This field is required'
14589 if (Roo.bootstrap.version == 4) {
14592 style : 'display:none'
14595 if (align ==='left' && this.fieldLabel.length) {
14597 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
14604 cls : 'control-label col-form-label',
14605 html : this.fieldLabel
14617 var labelCfg = cfg.cn[1];
14618 var contentCfg = cfg.cn[2];
14621 if(this.indicatorpos == 'right'){
14627 cls : 'control-label col-form-label',
14631 html : this.fieldLabel
14647 labelCfg = cfg.cn[0];
14648 contentCfg = cfg.cn[1];
14652 if(this.labelWidth > 12){
14653 labelCfg.style = "width: " + this.labelWidth + 'px';
14656 if(this.labelWidth < 13 && this.labelmd == 0){
14657 this.labelmd = this.labelWidth;
14660 if(this.labellg > 0){
14661 labelCfg.cls += ' col-lg-' + this.labellg;
14662 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14665 if(this.labelmd > 0){
14666 labelCfg.cls += ' col-md-' + this.labelmd;
14667 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14670 if(this.labelsm > 0){
14671 labelCfg.cls += ' col-sm-' + this.labelsm;
14672 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14675 if(this.labelxs > 0){
14676 labelCfg.cls += ' col-xs-' + this.labelxs;
14677 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14681 } else if ( this.fieldLabel.length) {
14682 // Roo.log(" label");
14687 //cls : 'input-group-addon',
14688 html : this.fieldLabel
14693 if(this.indicatorpos == 'right'){
14697 //cls : 'input-group-addon',
14698 html : this.fieldLabel
14708 // Roo.log(" no label && no align");
14715 ['xs','sm','md','lg'].map(function(size){
14716 if (settings[size]) {
14717 cfg.cls += ' col-' + size + '-' + settings[size];
14725 _initEventsCalled : false,
14728 initEvents: function()
14730 if (this._initEventsCalled) { // as we call render... prevent looping...
14733 this._initEventsCalled = true;
14736 throw "can not find store for combo";
14739 this.indicator = this.indicatorEl();
14741 this.store = Roo.factory(this.store, Roo.data);
14742 this.store.parent = this;
14744 // if we are building from html. then this element is so complex, that we can not really
14745 // use the rendered HTML.
14746 // so we have to trash and replace the previous code.
14747 if (Roo.XComponent.build_from_html) {
14748 // remove this element....
14749 var e = this.el.dom, k=0;
14750 while (e ) { e = e.previousSibling; ++k;}
14755 this.rendered = false;
14757 this.render(this.parent().getChildContainer(true), k);
14760 if(Roo.isIOS && this.useNativeIOS){
14761 this.initIOSView();
14769 if(Roo.isTouch && this.mobileTouchView){
14770 this.initTouchView();
14775 this.initTickableEvents();
14779 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
14781 if(this.hiddenName){
14783 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14785 this.hiddenField.dom.value =
14786 this.hiddenValue !== undefined ? this.hiddenValue :
14787 this.value !== undefined ? this.value : '';
14789 // prevent input submission
14790 this.el.dom.removeAttribute('name');
14791 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14796 // this.el.dom.setAttribute('autocomplete', 'off');
14799 var cls = 'x-combo-list';
14801 //this.list = new Roo.Layer({
14802 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
14808 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14809 _this.list.setWidth(lw);
14812 this.list.on('mouseover', this.onViewOver, this);
14813 this.list.on('mousemove', this.onViewMove, this);
14814 this.list.on('scroll', this.onViewScroll, this);
14817 this.list.swallowEvent('mousewheel');
14818 this.assetHeight = 0;
14821 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
14822 this.assetHeight += this.header.getHeight();
14825 this.innerList = this.list.createChild({cls:cls+'-inner'});
14826 this.innerList.on('mouseover', this.onViewOver, this);
14827 this.innerList.on('mousemove', this.onViewMove, this);
14828 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14830 if(this.allowBlank && !this.pageSize && !this.disableClear){
14831 this.footer = this.list.createChild({cls:cls+'-ft'});
14832 this.pageTb = new Roo.Toolbar(this.footer);
14836 this.footer = this.list.createChild({cls:cls+'-ft'});
14837 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
14838 {pageSize: this.pageSize});
14842 if (this.pageTb && this.allowBlank && !this.disableClear) {
14844 this.pageTb.add(new Roo.Toolbar.Fill(), {
14845 cls: 'x-btn-icon x-btn-clear',
14847 handler: function()
14850 _this.clearValue();
14851 _this.onSelect(false, -1);
14856 this.assetHeight += this.footer.getHeight();
14861 this.tpl = Roo.bootstrap.version == 4 ?
14862 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
14863 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
14866 this.view = new Roo.View(this.list, this.tpl, {
14867 singleSelect:true, store: this.store, selectedClass: this.selectedClass
14869 //this.view.wrapEl.setDisplayed(false);
14870 this.view.on('click', this.onViewClick, this);
14873 this.store.on('beforeload', this.onBeforeLoad, this);
14874 this.store.on('load', this.onLoad, this);
14875 this.store.on('loadexception', this.onLoadException, this);
14877 if(this.resizable){
14878 this.resizer = new Roo.Resizable(this.list, {
14879 pinned:true, handles:'se'
14881 this.resizer.on('resize', function(r, w, h){
14882 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
14883 this.listWidth = w;
14884 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
14885 this.restrictHeight();
14887 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
14890 if(!this.editable){
14891 this.editable = true;
14892 this.setEditable(false);
14897 if (typeof(this.events.add.listeners) != 'undefined') {
14899 this.addicon = this.wrap.createChild(
14900 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
14902 this.addicon.on('click', function(e) {
14903 this.fireEvent('add', this);
14906 if (typeof(this.events.edit.listeners) != 'undefined') {
14908 this.editicon = this.wrap.createChild(
14909 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
14910 if (this.addicon) {
14911 this.editicon.setStyle('margin-left', '40px');
14913 this.editicon.on('click', function(e) {
14915 // we fire even if inothing is selected..
14916 this.fireEvent('edit', this, this.lastData );
14922 this.keyNav = new Roo.KeyNav(this.inputEl(), {
14923 "up" : function(e){
14924 this.inKeyMode = true;
14928 "down" : function(e){
14929 if(!this.isExpanded()){
14930 this.onTriggerClick();
14932 this.inKeyMode = true;
14937 "enter" : function(e){
14938 // this.onViewClick();
14942 if(this.fireEvent("specialkey", this, e)){
14943 this.onViewClick(false);
14949 "esc" : function(e){
14953 "tab" : function(e){
14956 if(this.fireEvent("specialkey", this, e)){
14957 this.onViewClick(false);
14965 doRelay : function(foo, bar, hname){
14966 if(hname == 'down' || this.scope.isExpanded()){
14967 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14976 this.queryDelay = Math.max(this.queryDelay || 10,
14977 this.mode == 'local' ? 10 : 250);
14980 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14982 if(this.typeAhead){
14983 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14985 if(this.editable !== false){
14986 this.inputEl().on("keyup", this.onKeyUp, this);
14988 if(this.forceSelection){
14989 this.inputEl().on('blur', this.doForce, this);
14993 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14994 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14998 initTickableEvents: function()
15002 if(this.hiddenName){
15004 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15006 this.hiddenField.dom.value =
15007 this.hiddenValue !== undefined ? this.hiddenValue :
15008 this.value !== undefined ? this.value : '';
15010 // prevent input submission
15011 this.el.dom.removeAttribute('name');
15012 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15017 // this.list = this.el.select('ul.dropdown-menu',true).first();
15019 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15020 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15021 if(this.triggerList){
15022 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
15025 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
15026 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
15028 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
15029 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
15031 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
15032 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
15034 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
15035 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
15036 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
15039 this.cancelBtn.hide();
15044 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15045 _this.list.setWidth(lw);
15048 this.list.on('mouseover', this.onViewOver, this);
15049 this.list.on('mousemove', this.onViewMove, this);
15051 this.list.on('scroll', this.onViewScroll, this);
15054 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
15055 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
15058 this.view = new Roo.View(this.list, this.tpl, {
15063 selectedClass: this.selectedClass
15066 //this.view.wrapEl.setDisplayed(false);
15067 this.view.on('click', this.onViewClick, this);
15071 this.store.on('beforeload', this.onBeforeLoad, this);
15072 this.store.on('load', this.onLoad, this);
15073 this.store.on('loadexception', this.onLoadException, this);
15076 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
15077 "up" : function(e){
15078 this.inKeyMode = true;
15082 "down" : function(e){
15083 this.inKeyMode = true;
15087 "enter" : function(e){
15088 if(this.fireEvent("specialkey", this, e)){
15089 this.onViewClick(false);
15095 "esc" : function(e){
15096 this.onTickableFooterButtonClick(e, false, false);
15099 "tab" : function(e){
15100 this.fireEvent("specialkey", this, e);
15102 this.onTickableFooterButtonClick(e, false, false);
15109 doRelay : function(e, fn, key){
15110 if(this.scope.isExpanded()){
15111 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15120 this.queryDelay = Math.max(this.queryDelay || 10,
15121 this.mode == 'local' ? 10 : 250);
15124 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15126 if(this.typeAhead){
15127 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15130 if(this.editable !== false){
15131 this.tickableInputEl().on("keyup", this.onKeyUp, this);
15134 this.indicator = this.indicatorEl();
15136 if(this.indicator){
15137 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
15138 this.indicator.hide();
15143 onDestroy : function(){
15145 this.view.setStore(null);
15146 this.view.el.removeAllListeners();
15147 this.view.el.remove();
15148 this.view.purgeListeners();
15151 this.list.dom.innerHTML = '';
15155 this.store.un('beforeload', this.onBeforeLoad, this);
15156 this.store.un('load', this.onLoad, this);
15157 this.store.un('loadexception', this.onLoadException, this);
15159 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
15163 fireKey : function(e){
15164 if(e.isNavKeyPress() && !this.list.isVisible()){
15165 this.fireEvent("specialkey", this, e);
15170 onResize: function(w, h){
15171 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
15173 // if(typeof w != 'number'){
15174 // // we do not handle it!?!?
15177 // var tw = this.trigger.getWidth();
15178 // // tw += this.addicon ? this.addicon.getWidth() : 0;
15179 // // tw += this.editicon ? this.editicon.getWidth() : 0;
15181 // this.inputEl().setWidth( this.adjustWidth('input', x));
15183 // //this.trigger.setStyle('left', x+'px');
15185 // if(this.list && this.listWidth === undefined){
15186 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
15187 // this.list.setWidth(lw);
15188 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15196 * Allow or prevent the user from directly editing the field text. If false is passed,
15197 * the user will only be able to select from the items defined in the dropdown list. This method
15198 * is the runtime equivalent of setting the 'editable' config option at config time.
15199 * @param {Boolean} value True to allow the user to directly edit the field text
15201 setEditable : function(value){
15202 if(value == this.editable){
15205 this.editable = value;
15207 this.inputEl().dom.setAttribute('readOnly', true);
15208 this.inputEl().on('mousedown', this.onTriggerClick, this);
15209 this.inputEl().addClass('x-combo-noedit');
15211 this.inputEl().dom.setAttribute('readOnly', false);
15212 this.inputEl().un('mousedown', this.onTriggerClick, this);
15213 this.inputEl().removeClass('x-combo-noedit');
15219 onBeforeLoad : function(combo,opts){
15220 if(!this.hasFocus){
15224 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
15226 this.restrictHeight();
15227 this.selectedIndex = -1;
15231 onLoad : function(){
15233 this.hasQuery = false;
15235 if(!this.hasFocus){
15239 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15240 this.loading.hide();
15243 if(this.store.getCount() > 0){
15246 this.restrictHeight();
15247 if(this.lastQuery == this.allQuery){
15248 if(this.editable && !this.tickable){
15249 this.inputEl().dom.select();
15253 !this.selectByValue(this.value, true) &&
15256 !this.store.lastOptions ||
15257 typeof(this.store.lastOptions.add) == 'undefined' ||
15258 this.store.lastOptions.add != true
15261 this.select(0, true);
15264 if(this.autoFocus){
15267 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
15268 this.taTask.delay(this.typeAheadDelay);
15272 this.onEmptyResults();
15278 onLoadException : function()
15280 this.hasQuery = false;
15282 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15283 this.loading.hide();
15286 if(this.tickable && this.editable){
15291 // only causes errors at present
15292 //Roo.log(this.store.reader.jsonData);
15293 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
15295 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
15301 onTypeAhead : function(){
15302 if(this.store.getCount() > 0){
15303 var r = this.store.getAt(0);
15304 var newValue = r.data[this.displayField];
15305 var len = newValue.length;
15306 var selStart = this.getRawValue().length;
15308 if(selStart != len){
15309 this.setRawValue(newValue);
15310 this.selectText(selStart, newValue.length);
15316 onSelect : function(record, index){
15318 if(this.fireEvent('beforeselect', this, record, index) !== false){
15320 this.setFromData(index > -1 ? record.data : false);
15323 this.fireEvent('select', this, record, index);
15328 * Returns the currently selected field value or empty string if no value is set.
15329 * @return {String} value The selected value
15331 getValue : function()
15333 if(Roo.isIOS && this.useNativeIOS){
15334 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
15338 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
15341 if(this.valueField){
15342 return typeof this.value != 'undefined' ? this.value : '';
15344 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
15348 getRawValue : function()
15350 if(Roo.isIOS && this.useNativeIOS){
15351 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
15354 var v = this.inputEl().getValue();
15360 * Clears any text/value currently set in the field
15362 clearValue : function(){
15364 if(this.hiddenField){
15365 this.hiddenField.dom.value = '';
15368 this.setRawValue('');
15369 this.lastSelectionText = '';
15370 this.lastData = false;
15372 var close = this.closeTriggerEl();
15383 * Sets the specified value into the field. If the value finds a match, the corresponding record text
15384 * will be displayed in the field. If the value does not match the data value of an existing item,
15385 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
15386 * Otherwise the field will be blank (although the value will still be set).
15387 * @param {String} value The value to match
15389 setValue : function(v)
15391 if(Roo.isIOS && this.useNativeIOS){
15392 this.setIOSValue(v);
15402 if(this.valueField){
15403 var r = this.findRecord(this.valueField, v);
15405 text = r.data[this.displayField];
15406 }else if(this.valueNotFoundText !== undefined){
15407 text = this.valueNotFoundText;
15410 this.lastSelectionText = text;
15411 if(this.hiddenField){
15412 this.hiddenField.dom.value = v;
15414 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
15417 var close = this.closeTriggerEl();
15420 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
15426 * @property {Object} the last set data for the element
15431 * Sets the value of the field based on a object which is related to the record format for the store.
15432 * @param {Object} value the value to set as. or false on reset?
15434 setFromData : function(o){
15441 var dv = ''; // display value
15442 var vv = ''; // value value..
15444 if (this.displayField) {
15445 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15447 // this is an error condition!!!
15448 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15451 if(this.valueField){
15452 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
15455 var close = this.closeTriggerEl();
15458 if(dv.length || vv * 1 > 0){
15460 this.blockFocus=true;
15466 if(this.hiddenField){
15467 this.hiddenField.dom.value = vv;
15469 this.lastSelectionText = dv;
15470 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
15474 // no hidden field.. - we store the value in 'value', but still display
15475 // display field!!!!
15476 this.lastSelectionText = dv;
15477 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
15484 reset : function(){
15485 // overridden so that last data is reset..
15492 this.setValue(this.originalValue);
15493 //this.clearInvalid();
15494 this.lastData = false;
15496 this.view.clearSelections();
15502 findRecord : function(prop, value){
15504 if(this.store.getCount() > 0){
15505 this.store.each(function(r){
15506 if(r.data[prop] == value){
15516 getName: function()
15518 // returns hidden if it's set..
15519 if (!this.rendered) {return ''};
15520 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
15524 onViewMove : function(e, t){
15525 this.inKeyMode = false;
15529 onViewOver : function(e, t){
15530 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
15533 var item = this.view.findItemFromChild(t);
15536 var index = this.view.indexOf(item);
15537 this.select(index, false);
15542 onViewClick : function(view, doFocus, el, e)
15544 var index = this.view.getSelectedIndexes()[0];
15546 var r = this.store.getAt(index);
15550 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
15557 Roo.each(this.tickItems, function(v,k){
15559 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
15561 _this.tickItems.splice(k, 1);
15563 if(typeof(e) == 'undefined' && view == false){
15564 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
15576 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
15577 this.tickItems.push(r.data);
15580 if(typeof(e) == 'undefined' && view == false){
15581 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
15588 this.onSelect(r, index);
15590 if(doFocus !== false && !this.blockFocus){
15591 this.inputEl().focus();
15596 restrictHeight : function(){
15597 //this.innerList.dom.style.height = '';
15598 //var inner = this.innerList.dom;
15599 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
15600 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
15601 //this.list.beginUpdate();
15602 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
15603 this.list.alignTo(this.inputEl(), this.listAlign);
15604 this.list.alignTo(this.inputEl(), this.listAlign);
15605 //this.list.endUpdate();
15609 onEmptyResults : function(){
15611 if(this.tickable && this.editable){
15612 this.hasFocus = false;
15613 this.restrictHeight();
15621 * Returns true if the dropdown list is expanded, else false.
15623 isExpanded : function(){
15624 return this.list.isVisible();
15628 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
15629 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
15630 * @param {String} value The data value of the item to select
15631 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
15632 * selected item if it is not currently in view (defaults to true)
15633 * @return {Boolean} True if the value matched an item in the list, else false
15635 selectByValue : function(v, scrollIntoView){
15636 if(v !== undefined && v !== null){
15637 var r = this.findRecord(this.valueField || this.displayField, v);
15639 this.select(this.store.indexOf(r), scrollIntoView);
15647 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
15648 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
15649 * @param {Number} index The zero-based index of the list item to select
15650 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
15651 * selected item if it is not currently in view (defaults to true)
15653 select : function(index, scrollIntoView){
15654 this.selectedIndex = index;
15655 this.view.select(index);
15656 if(scrollIntoView !== false){
15657 var el = this.view.getNode(index);
15659 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
15662 this.list.scrollChildIntoView(el, false);
15668 selectNext : function(){
15669 var ct = this.store.getCount();
15671 if(this.selectedIndex == -1){
15673 }else if(this.selectedIndex < ct-1){
15674 this.select(this.selectedIndex+1);
15680 selectPrev : function(){
15681 var ct = this.store.getCount();
15683 if(this.selectedIndex == -1){
15685 }else if(this.selectedIndex != 0){
15686 this.select(this.selectedIndex-1);
15692 onKeyUp : function(e){
15693 if(this.editable !== false && !e.isSpecialKey()){
15694 this.lastKey = e.getKey();
15695 this.dqTask.delay(this.queryDelay);
15700 validateBlur : function(){
15701 return !this.list || !this.list.isVisible();
15705 initQuery : function(){
15707 var v = this.getRawValue();
15709 if(this.tickable && this.editable){
15710 v = this.tickableInputEl().getValue();
15717 doForce : function(){
15718 if(this.inputEl().dom.value.length > 0){
15719 this.inputEl().dom.value =
15720 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
15726 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
15727 * query allowing the query action to be canceled if needed.
15728 * @param {String} query The SQL query to execute
15729 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
15730 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
15731 * saved in the current store (defaults to false)
15733 doQuery : function(q, forceAll){
15735 if(q === undefined || q === null){
15740 forceAll: forceAll,
15744 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
15749 forceAll = qe.forceAll;
15750 if(forceAll === true || (q.length >= this.minChars)){
15752 this.hasQuery = true;
15754 if(this.lastQuery != q || this.alwaysQuery){
15755 this.lastQuery = q;
15756 if(this.mode == 'local'){
15757 this.selectedIndex = -1;
15759 this.store.clearFilter();
15762 if(this.specialFilter){
15763 this.fireEvent('specialfilter', this);
15768 this.store.filter(this.displayField, q);
15771 this.store.fireEvent("datachanged", this.store);
15778 this.store.baseParams[this.queryParam] = q;
15780 var options = {params : this.getParams(q)};
15783 options.add = true;
15784 options.params.start = this.page * this.pageSize;
15787 this.store.load(options);
15790 * this code will make the page width larger, at the beginning, the list not align correctly,
15791 * we should expand the list on onLoad
15792 * so command out it
15797 this.selectedIndex = -1;
15802 this.loadNext = false;
15806 getParams : function(q){
15808 //p[this.queryParam] = q;
15812 p.limit = this.pageSize;
15818 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
15820 collapse : function(){
15821 if(!this.isExpanded()){
15827 this.hasFocus = false;
15831 this.cancelBtn.hide();
15832 this.trigger.show();
15835 this.tickableInputEl().dom.value = '';
15836 this.tickableInputEl().blur();
15841 Roo.get(document).un('mousedown', this.collapseIf, this);
15842 Roo.get(document).un('mousewheel', this.collapseIf, this);
15843 if (!this.editable) {
15844 Roo.get(document).un('keydown', this.listKeyPress, this);
15846 this.fireEvent('collapse', this);
15852 collapseIf : function(e){
15853 var in_combo = e.within(this.el);
15854 var in_list = e.within(this.list);
15855 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
15857 if (in_combo || in_list || is_list) {
15858 //e.stopPropagation();
15863 this.onTickableFooterButtonClick(e, false, false);
15871 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
15873 expand : function(){
15875 if(this.isExpanded() || !this.hasFocus){
15879 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
15880 this.list.setWidth(lw);
15886 this.restrictHeight();
15890 this.tickItems = Roo.apply([], this.item);
15893 this.cancelBtn.show();
15894 this.trigger.hide();
15897 this.tickableInputEl().focus();
15902 Roo.get(document).on('mousedown', this.collapseIf, this);
15903 Roo.get(document).on('mousewheel', this.collapseIf, this);
15904 if (!this.editable) {
15905 Roo.get(document).on('keydown', this.listKeyPress, this);
15908 this.fireEvent('expand', this);
15912 // Implements the default empty TriggerField.onTriggerClick function
15913 onTriggerClick : function(e)
15915 Roo.log('trigger click');
15917 if(this.disabled || !this.triggerList){
15922 this.loadNext = false;
15924 if(this.isExpanded()){
15926 if (!this.blockFocus) {
15927 this.inputEl().focus();
15931 this.hasFocus = true;
15932 if(this.triggerAction == 'all') {
15933 this.doQuery(this.allQuery, true);
15935 this.doQuery(this.getRawValue());
15937 if (!this.blockFocus) {
15938 this.inputEl().focus();
15943 onTickableTriggerClick : function(e)
15950 this.loadNext = false;
15951 this.hasFocus = true;
15953 if(this.triggerAction == 'all') {
15954 this.doQuery(this.allQuery, true);
15956 this.doQuery(this.getRawValue());
15960 onSearchFieldClick : function(e)
15962 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
15963 this.onTickableFooterButtonClick(e, false, false);
15967 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
15972 this.loadNext = false;
15973 this.hasFocus = true;
15975 if(this.triggerAction == 'all') {
15976 this.doQuery(this.allQuery, true);
15978 this.doQuery(this.getRawValue());
15982 listKeyPress : function(e)
15984 //Roo.log('listkeypress');
15985 // scroll to first matching element based on key pres..
15986 if (e.isSpecialKey()) {
15989 var k = String.fromCharCode(e.getKey()).toUpperCase();
15992 var csel = this.view.getSelectedNodes();
15993 var cselitem = false;
15995 var ix = this.view.indexOf(csel[0]);
15996 cselitem = this.store.getAt(ix);
15997 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
16003 this.store.each(function(v) {
16005 // start at existing selection.
16006 if (cselitem.id == v.id) {
16012 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
16013 match = this.store.indexOf(v);
16019 if (match === false) {
16020 return true; // no more action?
16023 this.view.select(match);
16024 var sn = Roo.get(this.view.getSelectedNodes()[0]);
16025 sn.scrollIntoView(sn.dom.parentNode, false);
16028 onViewScroll : function(e, t){
16030 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){
16034 this.hasQuery = true;
16036 this.loading = this.list.select('.loading', true).first();
16038 if(this.loading === null){
16039 this.list.createChild({
16041 cls: 'loading roo-select2-more-results roo-select2-active',
16042 html: 'Loading more results...'
16045 this.loading = this.list.select('.loading', true).first();
16047 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
16049 this.loading.hide();
16052 this.loading.show();
16057 this.loadNext = true;
16059 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
16064 addItem : function(o)
16066 var dv = ''; // display value
16068 if (this.displayField) {
16069 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16071 // this is an error condition!!!
16072 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16079 var choice = this.choices.createChild({
16081 cls: 'roo-select2-search-choice',
16090 cls: 'roo-select2-search-choice-close fa fa-times',
16095 }, this.searchField);
16097 var close = choice.select('a.roo-select2-search-choice-close', true).first();
16099 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
16107 this.inputEl().dom.value = '';
16112 onRemoveItem : function(e, _self, o)
16114 e.preventDefault();
16116 this.lastItem = Roo.apply([], this.item);
16118 var index = this.item.indexOf(o.data) * 1;
16121 Roo.log('not this item?!');
16125 this.item.splice(index, 1);
16130 this.fireEvent('remove', this, e);
16136 syncValue : function()
16138 if(!this.item.length){
16145 Roo.each(this.item, function(i){
16146 if(_this.valueField){
16147 value.push(i[_this.valueField]);
16154 this.value = value.join(',');
16156 if(this.hiddenField){
16157 this.hiddenField.dom.value = this.value;
16160 this.store.fireEvent("datachanged", this.store);
16165 clearItem : function()
16167 if(!this.multiple){
16173 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
16181 if(this.tickable && !Roo.isTouch){
16182 this.view.refresh();
16186 inputEl: function ()
16188 if(Roo.isIOS && this.useNativeIOS){
16189 return this.el.select('select.roo-ios-select', true).first();
16192 if(Roo.isTouch && this.mobileTouchView){
16193 return this.el.select('input.form-control',true).first();
16197 return this.searchField;
16200 return this.el.select('input.form-control',true).first();
16203 onTickableFooterButtonClick : function(e, btn, el)
16205 e.preventDefault();
16207 this.lastItem = Roo.apply([], this.item);
16209 if(btn && btn.name == 'cancel'){
16210 this.tickItems = Roo.apply([], this.item);
16219 Roo.each(this.tickItems, function(o){
16227 validate : function()
16229 if(this.getVisibilityEl().hasClass('hidden')){
16233 var v = this.getRawValue();
16236 v = this.getValue();
16239 if(this.disabled || this.allowBlank || v.length){
16244 this.markInvalid();
16248 tickableInputEl : function()
16250 if(!this.tickable || !this.editable){
16251 return this.inputEl();
16254 return this.inputEl().select('.roo-select2-search-field-input', true).first();
16258 getAutoCreateTouchView : function()
16263 cls: 'form-group' //input-group
16269 type : this.inputType,
16270 cls : 'form-control x-combo-noedit',
16271 autocomplete: 'new-password',
16272 placeholder : this.placeholder || '',
16277 input.name = this.name;
16281 input.cls += ' input-' + this.size;
16284 if (this.disabled) {
16285 input.disabled = true;
16296 inputblock.cls += ' input-group';
16298 inputblock.cn.unshift({
16300 cls : 'input-group-addon input-group-prepend input-group-text',
16305 if(this.removable && !this.multiple){
16306 inputblock.cls += ' roo-removable';
16308 inputblock.cn.push({
16311 cls : 'roo-combo-removable-btn close'
16315 if(this.hasFeedback && !this.allowBlank){
16317 inputblock.cls += ' has-feedback';
16319 inputblock.cn.push({
16321 cls: 'glyphicon form-control-feedback'
16328 inputblock.cls += (this.before) ? '' : ' input-group';
16330 inputblock.cn.push({
16332 cls : 'input-group-addon input-group-append input-group-text',
16338 var ibwrap = inputblock;
16343 cls: 'roo-select2-choices',
16347 cls: 'roo-select2-search-field',
16360 cls: 'roo-select2-container input-group roo-touchview-combobox ',
16365 cls: 'form-hidden-field'
16371 if(!this.multiple && this.showToggleBtn){
16377 if (this.caret != false) {
16380 cls: 'fa fa-' + this.caret
16387 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
16389 Roo.bootstrap.version == 3 ? caret : '',
16392 cls: 'combobox-clear',
16406 combobox.cls += ' roo-select2-container-multi';
16409 var align = this.labelAlign || this.parentLabelAlign();
16411 if (align ==='left' && this.fieldLabel.length) {
16416 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
16417 tooltip : 'This field is required'
16421 cls : 'control-label col-form-label',
16422 html : this.fieldLabel
16433 var labelCfg = cfg.cn[1];
16434 var contentCfg = cfg.cn[2];
16437 if(this.indicatorpos == 'right'){
16442 cls : 'control-label col-form-label',
16446 html : this.fieldLabel
16450 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
16451 tooltip : 'This field is required'
16464 labelCfg = cfg.cn[0];
16465 contentCfg = cfg.cn[1];
16470 if(this.labelWidth > 12){
16471 labelCfg.style = "width: " + this.labelWidth + 'px';
16474 if(this.labelWidth < 13 && this.labelmd == 0){
16475 this.labelmd = this.labelWidth;
16478 if(this.labellg > 0){
16479 labelCfg.cls += ' col-lg-' + this.labellg;
16480 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
16483 if(this.labelmd > 0){
16484 labelCfg.cls += ' col-md-' + this.labelmd;
16485 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
16488 if(this.labelsm > 0){
16489 labelCfg.cls += ' col-sm-' + this.labelsm;
16490 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
16493 if(this.labelxs > 0){
16494 labelCfg.cls += ' col-xs-' + this.labelxs;
16495 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
16499 } else if ( this.fieldLabel.length) {
16503 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
16504 tooltip : 'This field is required'
16508 cls : 'control-label',
16509 html : this.fieldLabel
16520 if(this.indicatorpos == 'right'){
16524 cls : 'control-label',
16525 html : this.fieldLabel,
16529 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
16530 tooltip : 'This field is required'
16547 var settings = this;
16549 ['xs','sm','md','lg'].map(function(size){
16550 if (settings[size]) {
16551 cfg.cls += ' col-' + size + '-' + settings[size];
16558 initTouchView : function()
16560 this.renderTouchView();
16562 this.touchViewEl.on('scroll', function(){
16563 this.el.dom.scrollTop = 0;
16566 this.originalValue = this.getValue();
16568 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
16570 this.inputEl().on("click", this.showTouchView, this);
16571 if (this.triggerEl) {
16572 this.triggerEl.on("click", this.showTouchView, this);
16576 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
16577 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
16579 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
16581 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
16582 this.store.on('load', this.onTouchViewLoad, this);
16583 this.store.on('loadexception', this.onTouchViewLoadException, this);
16585 if(this.hiddenName){
16587 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
16589 this.hiddenField.dom.value =
16590 this.hiddenValue !== undefined ? this.hiddenValue :
16591 this.value !== undefined ? this.value : '';
16593 this.el.dom.removeAttribute('name');
16594 this.hiddenField.dom.setAttribute('name', this.hiddenName);
16598 this.choices = this.el.select('ul.roo-select2-choices', true).first();
16599 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
16602 if(this.removable && !this.multiple){
16603 var close = this.closeTriggerEl();
16605 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
16606 close.on('click', this.removeBtnClick, this, close);
16610 * fix the bug in Safari iOS8
16612 this.inputEl().on("focus", function(e){
16613 document.activeElement.blur();
16616 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
16623 renderTouchView : function()
16625 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
16626 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16628 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
16629 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16631 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
16632 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16633 this.touchViewBodyEl.setStyle('overflow', 'auto');
16635 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
16636 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16638 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
16639 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16643 showTouchView : function()
16649 this.touchViewHeaderEl.hide();
16651 if(this.modalTitle.length){
16652 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
16653 this.touchViewHeaderEl.show();
16656 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
16657 this.touchViewEl.show();
16659 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
16661 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
16662 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
16664 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
16666 if(this.modalTitle.length){
16667 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
16670 this.touchViewBodyEl.setHeight(bodyHeight);
16674 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
16676 this.touchViewEl.addClass('in');
16679 if(this._touchViewMask){
16680 Roo.get(document.body).addClass("x-body-masked");
16681 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
16682 this._touchViewMask.setStyle('z-index', 10000);
16683 this._touchViewMask.addClass('show');
16686 this.doTouchViewQuery();
16690 hideTouchView : function()
16692 this.touchViewEl.removeClass('in');
16696 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
16698 this.touchViewEl.setStyle('display', 'none');
16701 if(this._touchViewMask){
16702 this._touchViewMask.removeClass('show');
16703 Roo.get(document.body).removeClass("x-body-masked");
16707 setTouchViewValue : function()
16714 Roo.each(this.tickItems, function(o){
16719 this.hideTouchView();
16722 doTouchViewQuery : function()
16731 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
16735 if(!this.alwaysQuery || this.mode == 'local'){
16736 this.onTouchViewLoad();
16743 onTouchViewBeforeLoad : function(combo,opts)
16749 onTouchViewLoad : function()
16751 if(this.store.getCount() < 1){
16752 this.onTouchViewEmptyResults();
16756 this.clearTouchView();
16758 var rawValue = this.getRawValue();
16760 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
16762 this.tickItems = [];
16764 this.store.data.each(function(d, rowIndex){
16765 var row = this.touchViewListGroup.createChild(template);
16767 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
16768 row.addClass(d.data.cls);
16771 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16774 html : d.data[this.displayField]
16777 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
16778 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
16781 row.removeClass('selected');
16782 if(!this.multiple && this.valueField &&
16783 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
16786 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16787 row.addClass('selected');
16790 if(this.multiple && this.valueField &&
16791 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
16795 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16796 this.tickItems.push(d.data);
16799 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
16803 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
16805 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
16807 if(this.modalTitle.length){
16808 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
16811 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
16813 if(this.mobile_restrict_height && listHeight < bodyHeight){
16814 this.touchViewBodyEl.setHeight(listHeight);
16819 if(firstChecked && listHeight > bodyHeight){
16820 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
16825 onTouchViewLoadException : function()
16827 this.hideTouchView();
16830 onTouchViewEmptyResults : function()
16832 this.clearTouchView();
16834 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
16836 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
16840 clearTouchView : function()
16842 this.touchViewListGroup.dom.innerHTML = '';
16845 onTouchViewClick : function(e, el, o)
16847 e.preventDefault();
16850 var rowIndex = o.rowIndex;
16852 var r = this.store.getAt(rowIndex);
16854 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
16856 if(!this.multiple){
16857 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
16858 c.dom.removeAttribute('checked');
16861 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16863 this.setFromData(r.data);
16865 var close = this.closeTriggerEl();
16871 this.hideTouchView();
16873 this.fireEvent('select', this, r, rowIndex);
16878 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
16879 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
16880 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
16884 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16885 this.addItem(r.data);
16886 this.tickItems.push(r.data);
16890 getAutoCreateNativeIOS : function()
16893 cls: 'form-group' //input-group,
16898 cls : 'roo-ios-select'
16902 combobox.name = this.name;
16905 if (this.disabled) {
16906 combobox.disabled = true;
16909 var settings = this;
16911 ['xs','sm','md','lg'].map(function(size){
16912 if (settings[size]) {
16913 cfg.cls += ' col-' + size + '-' + settings[size];
16923 initIOSView : function()
16925 this.store.on('load', this.onIOSViewLoad, this);
16930 onIOSViewLoad : function()
16932 if(this.store.getCount() < 1){
16936 this.clearIOSView();
16938 if(this.allowBlank) {
16940 var default_text = '-- SELECT --';
16942 if(this.placeholder.length){
16943 default_text = this.placeholder;
16946 if(this.emptyTitle.length){
16947 default_text += ' - ' + this.emptyTitle + ' -';
16950 var opt = this.inputEl().createChild({
16953 html : default_text
16957 o[this.valueField] = 0;
16958 o[this.displayField] = default_text;
16960 this.ios_options.push({
16967 this.store.data.each(function(d, rowIndex){
16971 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16972 html = d.data[this.displayField];
16977 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16978 value = d.data[this.valueField];
16987 if(this.value == d.data[this.valueField]){
16988 option['selected'] = true;
16991 var opt = this.inputEl().createChild(option);
16993 this.ios_options.push({
17000 this.inputEl().on('change', function(){
17001 this.fireEvent('select', this);
17006 clearIOSView: function()
17008 this.inputEl().dom.innerHTML = '';
17010 this.ios_options = [];
17013 setIOSValue: function(v)
17017 if(!this.ios_options){
17021 Roo.each(this.ios_options, function(opts){
17023 opts.el.dom.removeAttribute('selected');
17025 if(opts.data[this.valueField] != v){
17029 opts.el.dom.setAttribute('selected', true);
17035 * @cfg {Boolean} grow
17039 * @cfg {Number} growMin
17043 * @cfg {Number} growMax
17052 Roo.apply(Roo.bootstrap.ComboBox, {
17056 cls: 'modal-header',
17078 cls: 'list-group-item',
17082 cls: 'roo-combobox-list-group-item-value'
17086 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
17100 listItemCheckbox : {
17102 cls: 'list-group-item',
17106 cls: 'roo-combobox-list-group-item-value'
17110 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
17126 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
17131 cls: 'modal-footer',
17139 cls: 'col-xs-6 text-left',
17142 cls: 'btn btn-danger roo-touch-view-cancel',
17148 cls: 'col-xs-6 text-right',
17151 cls: 'btn btn-success roo-touch-view-ok',
17162 Roo.apply(Roo.bootstrap.ComboBox, {
17164 touchViewTemplate : {
17166 cls: 'modal fade roo-combobox-touch-view',
17170 cls: 'modal-dialog',
17171 style : 'position:fixed', // we have to fix position....
17175 cls: 'modal-content',
17177 Roo.bootstrap.ComboBox.header,
17178 Roo.bootstrap.ComboBox.body,
17179 Roo.bootstrap.ComboBox.footer
17188 * Ext JS Library 1.1.1
17189 * Copyright(c) 2006-2007, Ext JS, LLC.
17191 * Originally Released Under LGPL - original licence link has changed is not relivant.
17194 * <script type="text/javascript">
17199 * @extends Roo.util.Observable
17200 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
17201 * This class also supports single and multi selection modes. <br>
17202 * Create a data model bound view:
17204 var store = new Roo.data.Store(...);
17206 var view = new Roo.View({
17208 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
17210 singleSelect: true,
17211 selectedClass: "ydataview-selected",
17215 // listen for node click?
17216 view.on("click", function(vw, index, node, e){
17217 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
17221 dataModel.load("foobar.xml");
17223 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
17225 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
17226 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
17228 * Note: old style constructor is still suported (container, template, config)
17231 * Create a new View
17232 * @param {Object} config The config object
17235 Roo.View = function(config, depreciated_tpl, depreciated_config){
17237 this.parent = false;
17239 if (typeof(depreciated_tpl) == 'undefined') {
17240 // new way.. - universal constructor.
17241 Roo.apply(this, config);
17242 this.el = Roo.get(this.el);
17245 this.el = Roo.get(config);
17246 this.tpl = depreciated_tpl;
17247 Roo.apply(this, depreciated_config);
17249 this.wrapEl = this.el.wrap().wrap();
17250 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
17253 if(typeof(this.tpl) == "string"){
17254 this.tpl = new Roo.Template(this.tpl);
17256 // support xtype ctors..
17257 this.tpl = new Roo.factory(this.tpl, Roo);
17261 this.tpl.compile();
17266 * @event beforeclick
17267 * Fires before a click is processed. Returns false to cancel the default action.
17268 * @param {Roo.View} this
17269 * @param {Number} index The index of the target node
17270 * @param {HTMLElement} node The target node
17271 * @param {Roo.EventObject} e The raw event object
17273 "beforeclick" : true,
17276 * Fires when a template node is clicked.
17277 * @param {Roo.View} this
17278 * @param {Number} index The index of the target node
17279 * @param {HTMLElement} node The target node
17280 * @param {Roo.EventObject} e The raw event object
17285 * Fires when a template node is double clicked.
17286 * @param {Roo.View} this
17287 * @param {Number} index The index of the target node
17288 * @param {HTMLElement} node The target node
17289 * @param {Roo.EventObject} e The raw event object
17293 * @event contextmenu
17294 * Fires when a template node is right clicked.
17295 * @param {Roo.View} this
17296 * @param {Number} index The index of the target node
17297 * @param {HTMLElement} node The target node
17298 * @param {Roo.EventObject} e The raw event object
17300 "contextmenu" : true,
17302 * @event selectionchange
17303 * Fires when the selected nodes change.
17304 * @param {Roo.View} this
17305 * @param {Array} selections Array of the selected nodes
17307 "selectionchange" : true,
17310 * @event beforeselect
17311 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
17312 * @param {Roo.View} this
17313 * @param {HTMLElement} node The node to be selected
17314 * @param {Array} selections Array of currently selected nodes
17316 "beforeselect" : true,
17318 * @event preparedata
17319 * Fires on every row to render, to allow you to change the data.
17320 * @param {Roo.View} this
17321 * @param {Object} data to be rendered (change this)
17323 "preparedata" : true
17331 "click": this.onClick,
17332 "dblclick": this.onDblClick,
17333 "contextmenu": this.onContextMenu,
17337 this.selections = [];
17339 this.cmp = new Roo.CompositeElementLite([]);
17341 this.store = Roo.factory(this.store, Roo.data);
17342 this.setStore(this.store, true);
17345 if ( this.footer && this.footer.xtype) {
17347 var fctr = this.wrapEl.appendChild(document.createElement("div"));
17349 this.footer.dataSource = this.store;
17350 this.footer.container = fctr;
17351 this.footer = Roo.factory(this.footer, Roo);
17352 fctr.insertFirst(this.el);
17354 // this is a bit insane - as the paging toolbar seems to detach the el..
17355 // dom.parentNode.parentNode.parentNode
17356 // they get detached?
17360 Roo.View.superclass.constructor.call(this);
17365 Roo.extend(Roo.View, Roo.util.Observable, {
17368 * @cfg {Roo.data.Store} store Data store to load data from.
17373 * @cfg {String|Roo.Element} el The container element.
17378 * @cfg {String|Roo.Template} tpl The template used by this View
17382 * @cfg {String} dataName the named area of the template to use as the data area
17383 * Works with domtemplates roo-name="name"
17387 * @cfg {String} selectedClass The css class to add to selected nodes
17389 selectedClass : "x-view-selected",
17391 * @cfg {String} emptyText The empty text to show when nothing is loaded.
17396 * @cfg {String} text to display on mask (default Loading)
17400 * @cfg {Boolean} multiSelect Allow multiple selection
17402 multiSelect : false,
17404 * @cfg {Boolean} singleSelect Allow single selection
17406 singleSelect: false,
17409 * @cfg {Boolean} toggleSelect - selecting
17411 toggleSelect : false,
17414 * @cfg {Boolean} tickable - selecting
17419 * Returns the element this view is bound to.
17420 * @return {Roo.Element}
17422 getEl : function(){
17423 return this.wrapEl;
17429 * Refreshes the view. - called by datachanged on the store. - do not call directly.
17431 refresh : function(){
17432 //Roo.log('refresh');
17435 // if we are using something like 'domtemplate', then
17436 // the what gets used is:
17437 // t.applySubtemplate(NAME, data, wrapping data..)
17438 // the outer template then get' applied with
17439 // the store 'extra data'
17440 // and the body get's added to the
17441 // roo-name="data" node?
17442 // <span class='roo-tpl-{name}'></span> ?????
17446 this.clearSelections();
17447 this.el.update("");
17449 var records = this.store.getRange();
17450 if(records.length < 1) {
17452 // is this valid?? = should it render a template??
17454 this.el.update(this.emptyText);
17458 if (this.dataName) {
17459 this.el.update(t.apply(this.store.meta)); //????
17460 el = this.el.child('.roo-tpl-' + this.dataName);
17463 for(var i = 0, len = records.length; i < len; i++){
17464 var data = this.prepareData(records[i].data, i, records[i]);
17465 this.fireEvent("preparedata", this, data, i, records[i]);
17467 var d = Roo.apply({}, data);
17470 Roo.apply(d, {'roo-id' : Roo.id()});
17474 Roo.each(this.parent.item, function(item){
17475 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
17478 Roo.apply(d, {'roo-data-checked' : 'checked'});
17482 html[html.length] = Roo.util.Format.trim(
17484 t.applySubtemplate(this.dataName, d, this.store.meta) :
17491 el.update(html.join(""));
17492 this.nodes = el.dom.childNodes;
17493 this.updateIndexes(0);
17498 * Function to override to reformat the data that is sent to
17499 * the template for each node.
17500 * DEPRICATED - use the preparedata event handler.
17501 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
17502 * a JSON object for an UpdateManager bound view).
17504 prepareData : function(data, index, record)
17506 this.fireEvent("preparedata", this, data, index, record);
17510 onUpdate : function(ds, record){
17511 // Roo.log('on update');
17512 this.clearSelections();
17513 var index = this.store.indexOf(record);
17514 var n = this.nodes[index];
17515 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
17516 n.parentNode.removeChild(n);
17517 this.updateIndexes(index, index);
17523 onAdd : function(ds, records, index)
17525 //Roo.log(['on Add', ds, records, index] );
17526 this.clearSelections();
17527 if(this.nodes.length == 0){
17531 var n = this.nodes[index];
17532 for(var i = 0, len = records.length; i < len; i++){
17533 var d = this.prepareData(records[i].data, i, records[i]);
17535 this.tpl.insertBefore(n, d);
17538 this.tpl.append(this.el, d);
17541 this.updateIndexes(index);
17544 onRemove : function(ds, record, index){
17545 // Roo.log('onRemove');
17546 this.clearSelections();
17547 var el = this.dataName ?
17548 this.el.child('.roo-tpl-' + this.dataName) :
17551 el.dom.removeChild(this.nodes[index]);
17552 this.updateIndexes(index);
17556 * Refresh an individual node.
17557 * @param {Number} index
17559 refreshNode : function(index){
17560 this.onUpdate(this.store, this.store.getAt(index));
17563 updateIndexes : function(startIndex, endIndex){
17564 var ns = this.nodes;
17565 startIndex = startIndex || 0;
17566 endIndex = endIndex || ns.length - 1;
17567 for(var i = startIndex; i <= endIndex; i++){
17568 ns[i].nodeIndex = i;
17573 * Changes the data store this view uses and refresh the view.
17574 * @param {Store} store
17576 setStore : function(store, initial){
17577 if(!initial && this.store){
17578 this.store.un("datachanged", this.refresh);
17579 this.store.un("add", this.onAdd);
17580 this.store.un("remove", this.onRemove);
17581 this.store.un("update", this.onUpdate);
17582 this.store.un("clear", this.refresh);
17583 this.store.un("beforeload", this.onBeforeLoad);
17584 this.store.un("load", this.onLoad);
17585 this.store.un("loadexception", this.onLoad);
17589 store.on("datachanged", this.refresh, this);
17590 store.on("add", this.onAdd, this);
17591 store.on("remove", this.onRemove, this);
17592 store.on("update", this.onUpdate, this);
17593 store.on("clear", this.refresh, this);
17594 store.on("beforeload", this.onBeforeLoad, this);
17595 store.on("load", this.onLoad, this);
17596 store.on("loadexception", this.onLoad, this);
17604 * onbeforeLoad - masks the loading area.
17607 onBeforeLoad : function(store,opts)
17609 //Roo.log('onBeforeLoad');
17611 this.el.update("");
17613 this.el.mask(this.mask ? this.mask : "Loading" );
17615 onLoad : function ()
17622 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
17623 * @param {HTMLElement} node
17624 * @return {HTMLElement} The template node
17626 findItemFromChild : function(node){
17627 var el = this.dataName ?
17628 this.el.child('.roo-tpl-' + this.dataName,true) :
17631 if(!node || node.parentNode == el){
17634 var p = node.parentNode;
17635 while(p && p != el){
17636 if(p.parentNode == el){
17645 onClick : function(e){
17646 var item = this.findItemFromChild(e.getTarget());
17648 var index = this.indexOf(item);
17649 if(this.onItemClick(item, index, e) !== false){
17650 this.fireEvent("click", this, index, item, e);
17653 this.clearSelections();
17658 onContextMenu : function(e){
17659 var item = this.findItemFromChild(e.getTarget());
17661 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
17666 onDblClick : function(e){
17667 var item = this.findItemFromChild(e.getTarget());
17669 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
17673 onItemClick : function(item, index, e)
17675 if(this.fireEvent("beforeclick", this, index, item, e) === false){
17678 if (this.toggleSelect) {
17679 var m = this.isSelected(item) ? 'unselect' : 'select';
17682 _t[m](item, true, false);
17685 if(this.multiSelect || this.singleSelect){
17686 if(this.multiSelect && e.shiftKey && this.lastSelection){
17687 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
17689 this.select(item, this.multiSelect && e.ctrlKey);
17690 this.lastSelection = item;
17693 if(!this.tickable){
17694 e.preventDefault();
17702 * Get the number of selected nodes.
17705 getSelectionCount : function(){
17706 return this.selections.length;
17710 * Get the currently selected nodes.
17711 * @return {Array} An array of HTMLElements
17713 getSelectedNodes : function(){
17714 return this.selections;
17718 * Get the indexes of the selected nodes.
17721 getSelectedIndexes : function(){
17722 var indexes = [], s = this.selections;
17723 for(var i = 0, len = s.length; i < len; i++){
17724 indexes.push(s[i].nodeIndex);
17730 * Clear all selections
17731 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
17733 clearSelections : function(suppressEvent){
17734 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
17735 this.cmp.elements = this.selections;
17736 this.cmp.removeClass(this.selectedClass);
17737 this.selections = [];
17738 if(!suppressEvent){
17739 this.fireEvent("selectionchange", this, this.selections);
17745 * Returns true if the passed node is selected
17746 * @param {HTMLElement/Number} node The node or node index
17747 * @return {Boolean}
17749 isSelected : function(node){
17750 var s = this.selections;
17754 node = this.getNode(node);
17755 return s.indexOf(node) !== -1;
17760 * @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
17761 * @param {Boolean} keepExisting (optional) true to keep existing selections
17762 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
17764 select : function(nodeInfo, keepExisting, suppressEvent){
17765 if(nodeInfo instanceof Array){
17767 this.clearSelections(true);
17769 for(var i = 0, len = nodeInfo.length; i < len; i++){
17770 this.select(nodeInfo[i], true, true);
17774 var node = this.getNode(nodeInfo);
17775 if(!node || this.isSelected(node)){
17776 return; // already selected.
17779 this.clearSelections(true);
17782 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
17783 Roo.fly(node).addClass(this.selectedClass);
17784 this.selections.push(node);
17785 if(!suppressEvent){
17786 this.fireEvent("selectionchange", this, this.selections);
17794 * @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
17795 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
17796 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
17798 unselect : function(nodeInfo, keepExisting, suppressEvent)
17800 if(nodeInfo instanceof Array){
17801 Roo.each(this.selections, function(s) {
17802 this.unselect(s, nodeInfo);
17806 var node = this.getNode(nodeInfo);
17807 if(!node || !this.isSelected(node)){
17808 //Roo.log("not selected");
17809 return; // not selected.
17813 Roo.each(this.selections, function(s) {
17815 Roo.fly(node).removeClass(this.selectedClass);
17822 this.selections= ns;
17823 this.fireEvent("selectionchange", this, this.selections);
17827 * Gets a template node.
17828 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
17829 * @return {HTMLElement} The node or null if it wasn't found
17831 getNode : function(nodeInfo){
17832 if(typeof nodeInfo == "string"){
17833 return document.getElementById(nodeInfo);
17834 }else if(typeof nodeInfo == "number"){
17835 return this.nodes[nodeInfo];
17841 * Gets a range template nodes.
17842 * @param {Number} startIndex
17843 * @param {Number} endIndex
17844 * @return {Array} An array of nodes
17846 getNodes : function(start, end){
17847 var ns = this.nodes;
17848 start = start || 0;
17849 end = typeof end == "undefined" ? ns.length - 1 : end;
17852 for(var i = start; i <= end; i++){
17856 for(var i = start; i >= end; i--){
17864 * Finds the index of the passed node
17865 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
17866 * @return {Number} The index of the node or -1
17868 indexOf : function(node){
17869 node = this.getNode(node);
17870 if(typeof node.nodeIndex == "number"){
17871 return node.nodeIndex;
17873 var ns = this.nodes;
17874 for(var i = 0, len = ns.length; i < len; i++){
17885 * based on jquery fullcalendar
17889 Roo.bootstrap = Roo.bootstrap || {};
17891 * @class Roo.bootstrap.Calendar
17892 * @extends Roo.bootstrap.Component
17893 * Bootstrap Calendar class
17894 * @cfg {Boolean} loadMask (true|false) default false
17895 * @cfg {Object} header generate the user specific header of the calendar, default false
17898 * Create a new Container
17899 * @param {Object} config The config object
17904 Roo.bootstrap.Calendar = function(config){
17905 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
17909 * Fires when a date is selected
17910 * @param {DatePicker} this
17911 * @param {Date} date The selected date
17915 * @event monthchange
17916 * Fires when the displayed month changes
17917 * @param {DatePicker} this
17918 * @param {Date} date The selected month
17920 'monthchange': true,
17922 * @event evententer
17923 * Fires when mouse over an event
17924 * @param {Calendar} this
17925 * @param {event} Event
17927 'evententer': true,
17929 * @event eventleave
17930 * Fires when the mouse leaves an
17931 * @param {Calendar} this
17934 'eventleave': true,
17936 * @event eventclick
17937 * Fires when the mouse click an
17938 * @param {Calendar} this
17947 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
17950 * @cfg {Number} startDay
17951 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
17959 getAutoCreate : function(){
17962 var fc_button = function(name, corner, style, content ) {
17963 return Roo.apply({},{
17965 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
17967 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
17970 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17981 style : 'width:100%',
17988 cls : 'fc-header-left',
17990 fc_button('prev', 'left', 'arrow', '‹' ),
17991 fc_button('next', 'right', 'arrow', '›' ),
17992 { tag: 'span', cls: 'fc-header-space' },
17993 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
18001 cls : 'fc-header-center',
18005 cls: 'fc-header-title',
18008 html : 'month / year'
18016 cls : 'fc-header-right',
18018 /* fc_button('month', 'left', '', 'month' ),
18019 fc_button('week', '', '', 'week' ),
18020 fc_button('day', 'right', '', 'day' )
18032 header = this.header;
18035 var cal_heads = function() {
18037 // fixme - handle this.
18039 for (var i =0; i < Date.dayNames.length; i++) {
18040 var d = Date.dayNames[i];
18043 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
18044 html : d.substring(0,3)
18048 ret[0].cls += ' fc-first';
18049 ret[6].cls += ' fc-last';
18052 var cal_cell = function(n) {
18055 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
18060 cls: 'fc-day-number',
18064 cls: 'fc-day-content',
18068 style: 'position: relative;' // height: 17px;
18080 var cal_rows = function() {
18083 for (var r = 0; r < 6; r++) {
18090 for (var i =0; i < Date.dayNames.length; i++) {
18091 var d = Date.dayNames[i];
18092 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
18095 row.cn[0].cls+=' fc-first';
18096 row.cn[0].cn[0].style = 'min-height:90px';
18097 row.cn[6].cls+=' fc-last';
18101 ret[0].cls += ' fc-first';
18102 ret[4].cls += ' fc-prev-last';
18103 ret[5].cls += ' fc-last';
18110 cls: 'fc-border-separate',
18111 style : 'width:100%',
18119 cls : 'fc-first fc-last',
18137 cls : 'fc-content',
18138 style : "position: relative;",
18141 cls : 'fc-view fc-view-month fc-grid',
18142 style : 'position: relative',
18143 unselectable : 'on',
18146 cls : 'fc-event-container',
18147 style : 'position:absolute;z-index:8;top:0;left:0;'
18165 initEvents : function()
18168 throw "can not find store for calendar";
18174 style: "text-align:center",
18178 style: "background-color:white;width:50%;margin:250 auto",
18182 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
18193 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
18195 var size = this.el.select('.fc-content', true).first().getSize();
18196 this.maskEl.setSize(size.width, size.height);
18197 this.maskEl.enableDisplayMode("block");
18198 if(!this.loadMask){
18199 this.maskEl.hide();
18202 this.store = Roo.factory(this.store, Roo.data);
18203 this.store.on('load', this.onLoad, this);
18204 this.store.on('beforeload', this.onBeforeLoad, this);
18208 this.cells = this.el.select('.fc-day',true);
18209 //Roo.log(this.cells);
18210 this.textNodes = this.el.query('.fc-day-number');
18211 this.cells.addClassOnOver('fc-state-hover');
18213 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
18214 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
18215 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
18216 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
18218 this.on('monthchange', this.onMonthChange, this);
18220 this.update(new Date().clearTime());
18223 resize : function() {
18224 var sz = this.el.getSize();
18226 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
18227 this.el.select('.fc-day-content div',true).setHeight(34);
18232 showPrevMonth : function(e){
18233 this.update(this.activeDate.add("mo", -1));
18235 showToday : function(e){
18236 this.update(new Date().clearTime());
18239 showNextMonth : function(e){
18240 this.update(this.activeDate.add("mo", 1));
18244 showPrevYear : function(){
18245 this.update(this.activeDate.add("y", -1));
18249 showNextYear : function(){
18250 this.update(this.activeDate.add("y", 1));
18255 update : function(date)
18257 var vd = this.activeDate;
18258 this.activeDate = date;
18259 // if(vd && this.el){
18260 // var t = date.getTime();
18261 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
18262 // Roo.log('using add remove');
18264 // this.fireEvent('monthchange', this, date);
18266 // this.cells.removeClass("fc-state-highlight");
18267 // this.cells.each(function(c){
18268 // if(c.dateValue == t){
18269 // c.addClass("fc-state-highlight");
18270 // setTimeout(function(){
18271 // try{c.dom.firstChild.focus();}catch(e){}
18281 var days = date.getDaysInMonth();
18283 var firstOfMonth = date.getFirstDateOfMonth();
18284 var startingPos = firstOfMonth.getDay()-this.startDay;
18286 if(startingPos < this.startDay){
18290 var pm = date.add(Date.MONTH, -1);
18291 var prevStart = pm.getDaysInMonth()-startingPos;
18293 this.cells = this.el.select('.fc-day',true);
18294 this.textNodes = this.el.query('.fc-day-number');
18295 this.cells.addClassOnOver('fc-state-hover');
18297 var cells = this.cells.elements;
18298 var textEls = this.textNodes;
18300 Roo.each(cells, function(cell){
18301 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
18304 days += startingPos;
18306 // convert everything to numbers so it's fast
18307 var day = 86400000;
18308 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
18311 //Roo.log(prevStart);
18313 var today = new Date().clearTime().getTime();
18314 var sel = date.clearTime().getTime();
18315 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
18316 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
18317 var ddMatch = this.disabledDatesRE;
18318 var ddText = this.disabledDatesText;
18319 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
18320 var ddaysText = this.disabledDaysText;
18321 var format = this.format;
18323 var setCellClass = function(cal, cell){
18327 //Roo.log('set Cell Class');
18329 var t = d.getTime();
18333 cell.dateValue = t;
18335 cell.className += " fc-today";
18336 cell.className += " fc-state-highlight";
18337 cell.title = cal.todayText;
18340 // disable highlight in other month..
18341 //cell.className += " fc-state-highlight";
18346 cell.className = " fc-state-disabled";
18347 cell.title = cal.minText;
18351 cell.className = " fc-state-disabled";
18352 cell.title = cal.maxText;
18356 if(ddays.indexOf(d.getDay()) != -1){
18357 cell.title = ddaysText;
18358 cell.className = " fc-state-disabled";
18361 if(ddMatch && format){
18362 var fvalue = d.dateFormat(format);
18363 if(ddMatch.test(fvalue)){
18364 cell.title = ddText.replace("%0", fvalue);
18365 cell.className = " fc-state-disabled";
18369 if (!cell.initialClassName) {
18370 cell.initialClassName = cell.dom.className;
18373 cell.dom.className = cell.initialClassName + ' ' + cell.className;
18378 for(; i < startingPos; i++) {
18379 textEls[i].innerHTML = (++prevStart);
18380 d.setDate(d.getDate()+1);
18382 cells[i].className = "fc-past fc-other-month";
18383 setCellClass(this, cells[i]);
18388 for(; i < days; i++){
18389 intDay = i - startingPos + 1;
18390 textEls[i].innerHTML = (intDay);
18391 d.setDate(d.getDate()+1);
18393 cells[i].className = ''; // "x-date-active";
18394 setCellClass(this, cells[i]);
18398 for(; i < 42; i++) {
18399 textEls[i].innerHTML = (++extraDays);
18400 d.setDate(d.getDate()+1);
18402 cells[i].className = "fc-future fc-other-month";
18403 setCellClass(this, cells[i]);
18406 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
18408 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
18410 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
18411 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
18413 if(totalRows != 6){
18414 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
18415 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
18418 this.fireEvent('monthchange', this, date);
18422 if(!this.internalRender){
18423 var main = this.el.dom.firstChild;
18424 var w = main.offsetWidth;
18425 this.el.setWidth(w + this.el.getBorderWidth("lr"));
18426 Roo.fly(main).setWidth(w);
18427 this.internalRender = true;
18428 // opera does not respect the auto grow header center column
18429 // then, after it gets a width opera refuses to recalculate
18430 // without a second pass
18431 if(Roo.isOpera && !this.secondPass){
18432 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
18433 this.secondPass = true;
18434 this.update.defer(10, this, [date]);
18441 findCell : function(dt) {
18442 dt = dt.clearTime().getTime();
18444 this.cells.each(function(c){
18445 //Roo.log("check " +c.dateValue + '?=' + dt);
18446 if(c.dateValue == dt){
18456 findCells : function(ev) {
18457 var s = ev.start.clone().clearTime().getTime();
18459 var e= ev.end.clone().clearTime().getTime();
18462 this.cells.each(function(c){
18463 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
18465 if(c.dateValue > e){
18468 if(c.dateValue < s){
18477 // findBestRow: function(cells)
18481 // for (var i =0 ; i < cells.length;i++) {
18482 // ret = Math.max(cells[i].rows || 0,ret);
18489 addItem : function(ev)
18491 // look for vertical location slot in
18492 var cells = this.findCells(ev);
18494 // ev.row = this.findBestRow(cells);
18496 // work out the location.
18500 for(var i =0; i < cells.length; i++) {
18502 cells[i].row = cells[0].row;
18505 cells[i].row = cells[i].row + 1;
18515 if (crow.start.getY() == cells[i].getY()) {
18517 crow.end = cells[i];
18534 cells[0].events.push(ev);
18536 this.calevents.push(ev);
18539 clearEvents: function() {
18541 if(!this.calevents){
18545 Roo.each(this.cells.elements, function(c){
18551 Roo.each(this.calevents, function(e) {
18552 Roo.each(e.els, function(el) {
18553 el.un('mouseenter' ,this.onEventEnter, this);
18554 el.un('mouseleave' ,this.onEventLeave, this);
18559 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
18565 renderEvents: function()
18569 this.cells.each(function(c) {
18578 if(c.row != c.events.length){
18579 r = 4 - (4 - (c.row - c.events.length));
18582 c.events = ev.slice(0, r);
18583 c.more = ev.slice(r);
18585 if(c.more.length && c.more.length == 1){
18586 c.events.push(c.more.pop());
18589 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
18593 this.cells.each(function(c) {
18595 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
18598 for (var e = 0; e < c.events.length; e++){
18599 var ev = c.events[e];
18600 var rows = ev.rows;
18602 for(var i = 0; i < rows.length; i++) {
18604 // how many rows should it span..
18607 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
18608 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
18610 unselectable : "on",
18613 cls: 'fc-event-inner',
18617 // cls: 'fc-event-time',
18618 // html : cells.length > 1 ? '' : ev.time
18622 cls: 'fc-event-title',
18623 html : String.format('{0}', ev.title)
18630 cls: 'ui-resizable-handle ui-resizable-e',
18631 html : '  '
18638 cfg.cls += ' fc-event-start';
18640 if ((i+1) == rows.length) {
18641 cfg.cls += ' fc-event-end';
18644 var ctr = _this.el.select('.fc-event-container',true).first();
18645 var cg = ctr.createChild(cfg);
18647 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
18648 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
18650 var r = (c.more.length) ? 1 : 0;
18651 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
18652 cg.setWidth(ebox.right - sbox.x -2);
18654 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
18655 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
18656 cg.on('click', _this.onEventClick, _this, ev);
18667 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
18668 style : 'position: absolute',
18669 unselectable : "on",
18672 cls: 'fc-event-inner',
18676 cls: 'fc-event-title',
18684 cls: 'ui-resizable-handle ui-resizable-e',
18685 html : '  '
18691 var ctr = _this.el.select('.fc-event-container',true).first();
18692 var cg = ctr.createChild(cfg);
18694 var sbox = c.select('.fc-day-content',true).first().getBox();
18695 var ebox = c.select('.fc-day-content',true).first().getBox();
18697 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
18698 cg.setWidth(ebox.right - sbox.x -2);
18700 cg.on('click', _this.onMoreEventClick, _this, c.more);
18710 onEventEnter: function (e, el,event,d) {
18711 this.fireEvent('evententer', this, el, event);
18714 onEventLeave: function (e, el,event,d) {
18715 this.fireEvent('eventleave', this, el, event);
18718 onEventClick: function (e, el,event,d) {
18719 this.fireEvent('eventclick', this, el, event);
18722 onMonthChange: function () {
18726 onMoreEventClick: function(e, el, more)
18730 this.calpopover.placement = 'right';
18731 this.calpopover.setTitle('More');
18733 this.calpopover.setContent('');
18735 var ctr = this.calpopover.el.select('.popover-content', true).first();
18737 Roo.each(more, function(m){
18739 cls : 'fc-event-hori fc-event-draggable',
18742 var cg = ctr.createChild(cfg);
18744 cg.on('click', _this.onEventClick, _this, m);
18747 this.calpopover.show(el);
18752 onLoad: function ()
18754 this.calevents = [];
18757 if(this.store.getCount() > 0){
18758 this.store.data.each(function(d){
18761 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
18762 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
18763 time : d.data.start_time,
18764 title : d.data.title,
18765 description : d.data.description,
18766 venue : d.data.venue
18771 this.renderEvents();
18773 if(this.calevents.length && this.loadMask){
18774 this.maskEl.hide();
18778 onBeforeLoad: function()
18780 this.clearEvents();
18782 this.maskEl.show();
18796 * @class Roo.bootstrap.Popover
18797 * @extends Roo.bootstrap.Component
18798 * Bootstrap Popover class
18799 * @cfg {String} html contents of the popover (or false to use children..)
18800 * @cfg {String} title of popover (or false to hide)
18801 * @cfg {String} placement how it is placed
18802 * @cfg {String} trigger click || hover (or false to trigger manually)
18803 * @cfg {String} over what (parent or false to trigger manually.)
18804 * @cfg {Number} delay - delay before showing
18807 * Create a new Popover
18808 * @param {Object} config The config object
18811 Roo.bootstrap.Popover = function(config){
18812 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
18818 * After the popover show
18820 * @param {Roo.bootstrap.Popover} this
18825 * After the popover hide
18827 * @param {Roo.bootstrap.Popover} this
18833 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
18835 title: 'Fill in a title',
18838 placement : 'right',
18839 trigger : 'hover', // hover
18845 can_build_overlaid : false,
18847 getChildContainer : function()
18849 return this.el.select('.popover-content',true).first();
18852 getAutoCreate : function(){
18855 cls : 'popover roo-dynamic',
18856 style: 'display:block',
18862 cls : 'popover-inner',
18866 cls: 'popover-title popover-header',
18870 cls : 'popover-content popover-body',
18881 setTitle: function(str)
18884 this.el.select('.popover-title',true).first().dom.innerHTML = str;
18886 setContent: function(str)
18889 this.el.select('.popover-content',true).first().dom.innerHTML = str;
18891 // as it get's added to the bottom of the page.
18892 onRender : function(ct, position)
18894 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18896 var cfg = Roo.apply({}, this.getAutoCreate());
18900 cfg.cls += ' ' + this.cls;
18903 cfg.style = this.style;
18905 //Roo.log("adding to ");
18906 this.el = Roo.get(document.body).createChild(cfg, position);
18907 // Roo.log(this.el);
18912 initEvents : function()
18914 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
18915 this.el.enableDisplayMode('block');
18917 if (this.over === false) {
18920 if (this.triggers === false) {
18923 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18924 var triggers = this.trigger ? this.trigger.split(' ') : [];
18925 Roo.each(triggers, function(trigger) {
18927 if (trigger == 'click') {
18928 on_el.on('click', this.toggle, this);
18929 } else if (trigger != 'manual') {
18930 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
18931 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
18933 on_el.on(eventIn ,this.enter, this);
18934 on_el.on(eventOut, this.leave, this);
18945 toggle : function () {
18946 this.hoverState == 'in' ? this.leave() : this.enter();
18949 enter : function () {
18951 clearTimeout(this.timeout);
18953 this.hoverState = 'in';
18955 if (!this.delay || !this.delay.show) {
18960 this.timeout = setTimeout(function () {
18961 if (_t.hoverState == 'in') {
18964 }, this.delay.show)
18967 leave : function() {
18968 clearTimeout(this.timeout);
18970 this.hoverState = 'out';
18972 if (!this.delay || !this.delay.hide) {
18977 this.timeout = setTimeout(function () {
18978 if (_t.hoverState == 'out') {
18981 }, this.delay.hide)
18984 show : function (on_el)
18987 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18991 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18992 if (this.html !== false) {
18993 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18995 this.el.removeClass([
18996 'fade','top','bottom', 'left', 'right','in',
18997 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18999 if (!this.title.length) {
19000 this.el.select('.popover-title',true).hide();
19003 var placement = typeof this.placement == 'function' ?
19004 this.placement.call(this, this.el, on_el) :
19007 var autoToken = /\s?auto?\s?/i;
19008 var autoPlace = autoToken.test(placement);
19010 placement = placement.replace(autoToken, '') || 'top';
19014 //this.el.setXY([0,0]);
19016 this.el.dom.style.display='block';
19017 this.el.addClass(placement);
19019 //this.el.appendTo(on_el);
19021 var p = this.getPosition();
19022 var box = this.el.getBox();
19027 var align = Roo.bootstrap.Popover.alignment[placement];
19030 this.el.alignTo(on_el, align[0],align[1]);
19031 //var arrow = this.el.select('.arrow',true).first();
19032 //arrow.set(align[2],
19034 this.el.addClass('in');
19037 if (this.el.hasClass('fade')) {
19041 this.hoverState = 'in';
19043 this.fireEvent('show', this);
19048 this.el.setXY([0,0]);
19049 this.el.removeClass('in');
19051 this.hoverState = null;
19053 this.fireEvent('hide', this);
19058 Roo.bootstrap.Popover.alignment = {
19059 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
19060 'right' : ['l-r', [10,0], 'left bs-popover-left'],
19061 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
19062 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
19073 * @class Roo.bootstrap.Progress
19074 * @extends Roo.bootstrap.Component
19075 * Bootstrap Progress class
19076 * @cfg {Boolean} striped striped of the progress bar
19077 * @cfg {Boolean} active animated of the progress bar
19081 * Create a new Progress
19082 * @param {Object} config The config object
19085 Roo.bootstrap.Progress = function(config){
19086 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
19089 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
19094 getAutoCreate : function(){
19102 cfg.cls += ' progress-striped';
19106 cfg.cls += ' active';
19125 * @class Roo.bootstrap.ProgressBar
19126 * @extends Roo.bootstrap.Component
19127 * Bootstrap ProgressBar class
19128 * @cfg {Number} aria_valuenow aria-value now
19129 * @cfg {Number} aria_valuemin aria-value min
19130 * @cfg {Number} aria_valuemax aria-value max
19131 * @cfg {String} label label for the progress bar
19132 * @cfg {String} panel (success | info | warning | danger )
19133 * @cfg {String} role role of the progress bar
19134 * @cfg {String} sr_only text
19138 * Create a new ProgressBar
19139 * @param {Object} config The config object
19142 Roo.bootstrap.ProgressBar = function(config){
19143 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
19146 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
19150 aria_valuemax : 100,
19156 getAutoCreate : function()
19161 cls: 'progress-bar',
19162 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
19174 cfg.role = this.role;
19177 if(this.aria_valuenow){
19178 cfg['aria-valuenow'] = this.aria_valuenow;
19181 if(this.aria_valuemin){
19182 cfg['aria-valuemin'] = this.aria_valuemin;
19185 if(this.aria_valuemax){
19186 cfg['aria-valuemax'] = this.aria_valuemax;
19189 if(this.label && !this.sr_only){
19190 cfg.html = this.label;
19194 cfg.cls += ' progress-bar-' + this.panel;
19200 update : function(aria_valuenow)
19202 this.aria_valuenow = aria_valuenow;
19204 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
19219 * @class Roo.bootstrap.TabGroup
19220 * @extends Roo.bootstrap.Column
19221 * Bootstrap Column class
19222 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
19223 * @cfg {Boolean} carousel true to make the group behave like a carousel
19224 * @cfg {Boolean} bullets show bullets for the panels
19225 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
19226 * @cfg {Number} timer auto slide timer .. default 0 millisecond
19227 * @cfg {Boolean} showarrow (true|false) show arrow default true
19230 * Create a new TabGroup
19231 * @param {Object} config The config object
19234 Roo.bootstrap.TabGroup = function(config){
19235 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
19237 this.navId = Roo.id();
19240 Roo.bootstrap.TabGroup.register(this);
19244 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
19247 transition : false,
19252 slideOnTouch : false,
19255 getAutoCreate : function()
19257 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
19259 cfg.cls += ' tab-content';
19261 if (this.carousel) {
19262 cfg.cls += ' carousel slide';
19265 cls : 'carousel-inner',
19269 if(this.bullets && !Roo.isTouch){
19272 cls : 'carousel-bullets',
19276 if(this.bullets_cls){
19277 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
19284 cfg.cn[0].cn.push(bullets);
19287 if(this.showarrow){
19288 cfg.cn[0].cn.push({
19290 class : 'carousel-arrow',
19294 class : 'carousel-prev',
19298 class : 'fa fa-chevron-left'
19304 class : 'carousel-next',
19308 class : 'fa fa-chevron-right'
19321 initEvents: function()
19323 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
19324 // this.el.on("touchstart", this.onTouchStart, this);
19327 if(this.autoslide){
19330 this.slideFn = window.setInterval(function() {
19331 _this.showPanelNext();
19335 if(this.showarrow){
19336 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
19337 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
19343 // onTouchStart : function(e, el, o)
19345 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
19349 // this.showPanelNext();
19353 getChildContainer : function()
19355 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
19359 * register a Navigation item
19360 * @param {Roo.bootstrap.NavItem} the navitem to add
19362 register : function(item)
19364 this.tabs.push( item);
19365 item.navId = this.navId; // not really needed..
19370 getActivePanel : function()
19373 Roo.each(this.tabs, function(t) {
19383 getPanelByName : function(n)
19386 Roo.each(this.tabs, function(t) {
19387 if (t.tabId == n) {
19395 indexOfPanel : function(p)
19398 Roo.each(this.tabs, function(t,i) {
19399 if (t.tabId == p.tabId) {
19408 * show a specific panel
19409 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
19410 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
19412 showPanel : function (pan)
19414 if(this.transition || typeof(pan) == 'undefined'){
19415 Roo.log("waiting for the transitionend");
19419 if (typeof(pan) == 'number') {
19420 pan = this.tabs[pan];
19423 if (typeof(pan) == 'string') {
19424 pan = this.getPanelByName(pan);
19427 var cur = this.getActivePanel();
19430 Roo.log('pan or acitve pan is undefined');
19434 if (pan.tabId == this.getActivePanel().tabId) {
19438 if (false === cur.fireEvent('beforedeactivate')) {
19442 if(this.bullets > 0 && !Roo.isTouch){
19443 this.setActiveBullet(this.indexOfPanel(pan));
19446 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
19448 //class="carousel-item carousel-item-next carousel-item-left"
19450 this.transition = true;
19451 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
19452 var lr = dir == 'next' ? 'left' : 'right';
19453 pan.el.addClass(dir); // or prev
19454 pan.el.addClass('carousel-item-' + dir); // or prev
19455 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
19456 cur.el.addClass(lr); // or right
19457 pan.el.addClass(lr);
19458 cur.el.addClass('carousel-item-' +lr); // or right
19459 pan.el.addClass('carousel-item-' +lr);
19463 cur.el.on('transitionend', function() {
19464 Roo.log("trans end?");
19466 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
19467 pan.setActive(true);
19469 cur.el.removeClass([lr, 'carousel-item-' + lr]);
19470 cur.setActive(false);
19472 _this.transition = false;
19474 }, this, { single: true } );
19479 cur.setActive(false);
19480 pan.setActive(true);
19485 showPanelNext : function()
19487 var i = this.indexOfPanel(this.getActivePanel());
19489 if (i >= this.tabs.length - 1 && !this.autoslide) {
19493 if (i >= this.tabs.length - 1 && this.autoslide) {
19497 this.showPanel(this.tabs[i+1]);
19500 showPanelPrev : function()
19502 var i = this.indexOfPanel(this.getActivePanel());
19504 if (i < 1 && !this.autoslide) {
19508 if (i < 1 && this.autoslide) {
19509 i = this.tabs.length;
19512 this.showPanel(this.tabs[i-1]);
19516 addBullet: function()
19518 if(!this.bullets || Roo.isTouch){
19521 var ctr = this.el.select('.carousel-bullets',true).first();
19522 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
19523 var bullet = ctr.createChild({
19524 cls : 'bullet bullet-' + i
19525 },ctr.dom.lastChild);
19530 bullet.on('click', (function(e, el, o, ii, t){
19532 e.preventDefault();
19534 this.showPanel(ii);
19536 if(this.autoslide && this.slideFn){
19537 clearInterval(this.slideFn);
19538 this.slideFn = window.setInterval(function() {
19539 _this.showPanelNext();
19543 }).createDelegate(this, [i, bullet], true));
19548 setActiveBullet : function(i)
19554 Roo.each(this.el.select('.bullet', true).elements, function(el){
19555 el.removeClass('selected');
19558 var bullet = this.el.select('.bullet-' + i, true).first();
19564 bullet.addClass('selected');
19575 Roo.apply(Roo.bootstrap.TabGroup, {
19579 * register a Navigation Group
19580 * @param {Roo.bootstrap.NavGroup} the navgroup to add
19582 register : function(navgrp)
19584 this.groups[navgrp.navId] = navgrp;
19588 * fetch a Navigation Group based on the navigation ID
19589 * if one does not exist , it will get created.
19590 * @param {string} the navgroup to add
19591 * @returns {Roo.bootstrap.NavGroup} the navgroup
19593 get: function(navId) {
19594 if (typeof(this.groups[navId]) == 'undefined') {
19595 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
19597 return this.groups[navId] ;
19612 * @class Roo.bootstrap.TabPanel
19613 * @extends Roo.bootstrap.Component
19614 * Bootstrap TabPanel class
19615 * @cfg {Boolean} active panel active
19616 * @cfg {String} html panel content
19617 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
19618 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
19619 * @cfg {String} href click to link..
19623 * Create a new TabPanel
19624 * @param {Object} config The config object
19627 Roo.bootstrap.TabPanel = function(config){
19628 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
19632 * Fires when the active status changes
19633 * @param {Roo.bootstrap.TabPanel} this
19634 * @param {Boolean} state the new state
19639 * @event beforedeactivate
19640 * Fires before a tab is de-activated - can be used to do validation on a form.
19641 * @param {Roo.bootstrap.TabPanel} this
19642 * @return {Boolean} false if there is an error
19645 'beforedeactivate': true
19648 this.tabId = this.tabId || Roo.id();
19652 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
19660 getAutoCreate : function(){
19665 // item is needed for carousel - not sure if it has any effect otherwise
19666 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
19667 html: this.html || ''
19671 cfg.cls += ' active';
19675 cfg.tabId = this.tabId;
19683 initEvents: function()
19685 var p = this.parent();
19687 this.navId = this.navId || p.navId;
19689 if (typeof(this.navId) != 'undefined') {
19690 // not really needed.. but just in case.. parent should be a NavGroup.
19691 var tg = Roo.bootstrap.TabGroup.get(this.navId);
19695 var i = tg.tabs.length - 1;
19697 if(this.active && tg.bullets > 0 && i < tg.bullets){
19698 tg.setActiveBullet(i);
19702 this.el.on('click', this.onClick, this);
19705 this.el.on("touchstart", this.onTouchStart, this);
19706 this.el.on("touchmove", this.onTouchMove, this);
19707 this.el.on("touchend", this.onTouchEnd, this);
19712 onRender : function(ct, position)
19714 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
19717 setActive : function(state)
19719 Roo.log("panel - set active " + this.tabId + "=" + state);
19721 this.active = state;
19723 this.el.removeClass('active');
19725 } else if (!this.el.hasClass('active')) {
19726 this.el.addClass('active');
19729 this.fireEvent('changed', this, state);
19732 onClick : function(e)
19734 e.preventDefault();
19736 if(!this.href.length){
19740 window.location.href = this.href;
19749 onTouchStart : function(e)
19751 this.swiping = false;
19753 this.startX = e.browserEvent.touches[0].clientX;
19754 this.startY = e.browserEvent.touches[0].clientY;
19757 onTouchMove : function(e)
19759 this.swiping = true;
19761 this.endX = e.browserEvent.touches[0].clientX;
19762 this.endY = e.browserEvent.touches[0].clientY;
19765 onTouchEnd : function(e)
19772 var tabGroup = this.parent();
19774 if(this.endX > this.startX){ // swiping right
19775 tabGroup.showPanelPrev();
19779 if(this.startX > this.endX){ // swiping left
19780 tabGroup.showPanelNext();
19799 * @class Roo.bootstrap.DateField
19800 * @extends Roo.bootstrap.Input
19801 * Bootstrap DateField class
19802 * @cfg {Number} weekStart default 0
19803 * @cfg {String} viewMode default empty, (months|years)
19804 * @cfg {String} minViewMode default empty, (months|years)
19805 * @cfg {Number} startDate default -Infinity
19806 * @cfg {Number} endDate default Infinity
19807 * @cfg {Boolean} todayHighlight default false
19808 * @cfg {Boolean} todayBtn default false
19809 * @cfg {Boolean} calendarWeeks default false
19810 * @cfg {Object} daysOfWeekDisabled default empty
19811 * @cfg {Boolean} singleMode default false (true | false)
19813 * @cfg {Boolean} keyboardNavigation default true
19814 * @cfg {String} language default en
19817 * Create a new DateField
19818 * @param {Object} config The config object
19821 Roo.bootstrap.DateField = function(config){
19822 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
19826 * Fires when this field show.
19827 * @param {Roo.bootstrap.DateField} this
19828 * @param {Mixed} date The date value
19833 * Fires when this field hide.
19834 * @param {Roo.bootstrap.DateField} this
19835 * @param {Mixed} date The date value
19840 * Fires when select a date.
19841 * @param {Roo.bootstrap.DateField} this
19842 * @param {Mixed} date The date value
19846 * @event beforeselect
19847 * Fires when before select a date.
19848 * @param {Roo.bootstrap.DateField} this
19849 * @param {Mixed} date The date value
19851 beforeselect : true
19855 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
19858 * @cfg {String} format
19859 * The default date format string which can be overriden for localization support. The format must be
19860 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
19864 * @cfg {String} altFormats
19865 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
19866 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
19868 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
19876 todayHighlight : false,
19882 keyboardNavigation: true,
19884 calendarWeeks: false,
19886 startDate: -Infinity,
19890 daysOfWeekDisabled: [],
19894 singleMode : false,
19896 UTCDate: function()
19898 return new Date(Date.UTC.apply(Date, arguments));
19901 UTCToday: function()
19903 var today = new Date();
19904 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
19907 getDate: function() {
19908 var d = this.getUTCDate();
19909 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
19912 getUTCDate: function() {
19916 setDate: function(d) {
19917 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
19920 setUTCDate: function(d) {
19922 this.setValue(this.formatDate(this.date));
19925 onRender: function(ct, position)
19928 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
19930 this.language = this.language || 'en';
19931 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
19932 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
19934 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
19935 this.format = this.format || 'm/d/y';
19936 this.isInline = false;
19937 this.isInput = true;
19938 this.component = this.el.select('.add-on', true).first() || false;
19939 this.component = (this.component && this.component.length === 0) ? false : this.component;
19940 this.hasInput = this.component && this.inputEl().length;
19942 if (typeof(this.minViewMode === 'string')) {
19943 switch (this.minViewMode) {
19945 this.minViewMode = 1;
19948 this.minViewMode = 2;
19951 this.minViewMode = 0;
19956 if (typeof(this.viewMode === 'string')) {
19957 switch (this.viewMode) {
19970 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
19972 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
19974 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19976 this.picker().on('mousedown', this.onMousedown, this);
19977 this.picker().on('click', this.onClick, this);
19979 this.picker().addClass('datepicker-dropdown');
19981 this.startViewMode = this.viewMode;
19983 if(this.singleMode){
19984 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19985 v.setVisibilityMode(Roo.Element.DISPLAY);
19989 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19990 v.setStyle('width', '189px');
19994 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19995 if(!this.calendarWeeks){
20000 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20001 v.attr('colspan', function(i, val){
20002 return parseInt(val) + 1;
20007 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
20009 this.setStartDate(this.startDate);
20010 this.setEndDate(this.endDate);
20012 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
20019 if(this.isInline) {
20024 picker : function()
20026 return this.pickerEl;
20027 // return this.el.select('.datepicker', true).first();
20030 fillDow: function()
20032 var dowCnt = this.weekStart;
20041 if(this.calendarWeeks){
20049 while (dowCnt < this.weekStart + 7) {
20053 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
20057 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
20060 fillMonths: function()
20063 var months = this.picker().select('>.datepicker-months td', true).first();
20065 months.dom.innerHTML = '';
20071 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
20074 months.createChild(month);
20081 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;
20083 if (this.date < this.startDate) {
20084 this.viewDate = new Date(this.startDate);
20085 } else if (this.date > this.endDate) {
20086 this.viewDate = new Date(this.endDate);
20088 this.viewDate = new Date(this.date);
20096 var d = new Date(this.viewDate),
20097 year = d.getUTCFullYear(),
20098 month = d.getUTCMonth(),
20099 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
20100 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
20101 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
20102 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
20103 currentDate = this.date && this.date.valueOf(),
20104 today = this.UTCToday();
20106 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
20108 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20110 // this.picker.select('>tfoot th.today').
20111 // .text(dates[this.language].today)
20112 // .toggle(this.todayBtn !== false);
20114 this.updateNavArrows();
20117 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
20119 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
20121 prevMonth.setUTCDate(day);
20123 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
20125 var nextMonth = new Date(prevMonth);
20127 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
20129 nextMonth = nextMonth.valueOf();
20131 var fillMonths = false;
20133 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
20135 while(prevMonth.valueOf() <= nextMonth) {
20138 if (prevMonth.getUTCDay() === this.weekStart) {
20140 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
20148 if(this.calendarWeeks){
20149 // ISO 8601: First week contains first thursday.
20150 // ISO also states week starts on Monday, but we can be more abstract here.
20152 // Start of current week: based on weekstart/current date
20153 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
20154 // Thursday of this week
20155 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
20156 // First Thursday of year, year from thursday
20157 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
20158 // Calendar week: ms between thursdays, div ms per day, div 7 days
20159 calWeek = (th - yth) / 864e5 / 7 + 1;
20161 fillMonths.cn.push({
20169 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
20171 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
20174 if (this.todayHighlight &&
20175 prevMonth.getUTCFullYear() == today.getFullYear() &&
20176 prevMonth.getUTCMonth() == today.getMonth() &&
20177 prevMonth.getUTCDate() == today.getDate()) {
20178 clsName += ' today';
20181 if (currentDate && prevMonth.valueOf() === currentDate) {
20182 clsName += ' active';
20185 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
20186 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
20187 clsName += ' disabled';
20190 fillMonths.cn.push({
20192 cls: 'day ' + clsName,
20193 html: prevMonth.getDate()
20196 prevMonth.setDate(prevMonth.getDate()+1);
20199 var currentYear = this.date && this.date.getUTCFullYear();
20200 var currentMonth = this.date && this.date.getUTCMonth();
20202 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
20204 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
20205 v.removeClass('active');
20207 if(currentYear === year && k === currentMonth){
20208 v.addClass('active');
20211 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
20212 v.addClass('disabled');
20218 year = parseInt(year/10, 10) * 10;
20220 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
20222 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
20225 for (var i = -1; i < 11; i++) {
20226 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
20228 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
20236 showMode: function(dir)
20239 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
20242 Roo.each(this.picker().select('>div',true).elements, function(v){
20243 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20246 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
20251 if(this.isInline) {
20255 this.picker().removeClass(['bottom', 'top']);
20257 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20259 * place to the top of element!
20263 this.picker().addClass('top');
20264 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20269 this.picker().addClass('bottom');
20271 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20274 parseDate : function(value)
20276 if(!value || value instanceof Date){
20279 var v = Date.parseDate(value, this.format);
20280 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
20281 v = Date.parseDate(value, 'Y-m-d');
20283 if(!v && this.altFormats){
20284 if(!this.altFormatsArray){
20285 this.altFormatsArray = this.altFormats.split("|");
20287 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
20288 v = Date.parseDate(value, this.altFormatsArray[i]);
20294 formatDate : function(date, fmt)
20296 return (!date || !(date instanceof Date)) ?
20297 date : date.dateFormat(fmt || this.format);
20300 onFocus : function()
20302 Roo.bootstrap.DateField.superclass.onFocus.call(this);
20306 onBlur : function()
20308 Roo.bootstrap.DateField.superclass.onBlur.call(this);
20310 var d = this.inputEl().getValue();
20317 showPopup : function()
20319 this.picker().show();
20323 this.fireEvent('showpopup', this, this.date);
20326 hidePopup : function()
20328 if(this.isInline) {
20331 this.picker().hide();
20332 this.viewMode = this.startViewMode;
20335 this.fireEvent('hidepopup', this, this.date);
20339 onMousedown: function(e)
20341 e.stopPropagation();
20342 e.preventDefault();
20347 Roo.bootstrap.DateField.superclass.keyup.call(this);
20351 setValue: function(v)
20353 if(this.fireEvent('beforeselect', this, v) !== false){
20354 var d = new Date(this.parseDate(v) ).clearTime();
20356 if(isNaN(d.getTime())){
20357 this.date = this.viewDate = '';
20358 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
20362 v = this.formatDate(d);
20364 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
20366 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
20370 this.fireEvent('select', this, this.date);
20374 getValue: function()
20376 return this.formatDate(this.date);
20379 fireKey: function(e)
20381 if (!this.picker().isVisible()){
20382 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20388 var dateChanged = false,
20390 newDate, newViewDate;
20395 e.preventDefault();
20399 if (!this.keyboardNavigation) {
20402 dir = e.keyCode == 37 ? -1 : 1;
20405 newDate = this.moveYear(this.date, dir);
20406 newViewDate = this.moveYear(this.viewDate, dir);
20407 } else if (e.shiftKey){
20408 newDate = this.moveMonth(this.date, dir);
20409 newViewDate = this.moveMonth(this.viewDate, dir);
20411 newDate = new Date(this.date);
20412 newDate.setUTCDate(this.date.getUTCDate() + dir);
20413 newViewDate = new Date(this.viewDate);
20414 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
20416 if (this.dateWithinRange(newDate)){
20417 this.date = newDate;
20418 this.viewDate = newViewDate;
20419 this.setValue(this.formatDate(this.date));
20421 e.preventDefault();
20422 dateChanged = true;
20427 if (!this.keyboardNavigation) {
20430 dir = e.keyCode == 38 ? -1 : 1;
20432 newDate = this.moveYear(this.date, dir);
20433 newViewDate = this.moveYear(this.viewDate, dir);
20434 } else if (e.shiftKey){
20435 newDate = this.moveMonth(this.date, dir);
20436 newViewDate = this.moveMonth(this.viewDate, dir);
20438 newDate = new Date(this.date);
20439 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
20440 newViewDate = new Date(this.viewDate);
20441 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
20443 if (this.dateWithinRange(newDate)){
20444 this.date = newDate;
20445 this.viewDate = newViewDate;
20446 this.setValue(this.formatDate(this.date));
20448 e.preventDefault();
20449 dateChanged = true;
20453 this.setValue(this.formatDate(this.date));
20455 e.preventDefault();
20458 this.setValue(this.formatDate(this.date));
20472 onClick: function(e)
20474 e.stopPropagation();
20475 e.preventDefault();
20477 var target = e.getTarget();
20479 if(target.nodeName.toLowerCase() === 'i'){
20480 target = Roo.get(target).dom.parentNode;
20483 var nodeName = target.nodeName;
20484 var className = target.className;
20485 var html = target.innerHTML;
20486 //Roo.log(nodeName);
20488 switch(nodeName.toLowerCase()) {
20490 switch(className) {
20496 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
20497 switch(this.viewMode){
20499 this.viewDate = this.moveMonth(this.viewDate, dir);
20503 this.viewDate = this.moveYear(this.viewDate, dir);
20509 var date = new Date();
20510 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
20512 this.setValue(this.formatDate(this.date));
20519 if (className.indexOf('disabled') < 0) {
20520 this.viewDate.setUTCDate(1);
20521 if (className.indexOf('month') > -1) {
20522 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
20524 var year = parseInt(html, 10) || 0;
20525 this.viewDate.setUTCFullYear(year);
20529 if(this.singleMode){
20530 this.setValue(this.formatDate(this.viewDate));
20541 //Roo.log(className);
20542 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
20543 var day = parseInt(html, 10) || 1;
20544 var year = this.viewDate.getUTCFullYear(),
20545 month = this.viewDate.getUTCMonth();
20547 if (className.indexOf('old') > -1) {
20554 } else if (className.indexOf('new') > -1) {
20562 //Roo.log([year,month,day]);
20563 this.date = this.UTCDate(year, month, day,0,0,0,0);
20564 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
20566 //Roo.log(this.formatDate(this.date));
20567 this.setValue(this.formatDate(this.date));
20574 setStartDate: function(startDate)
20576 this.startDate = startDate || -Infinity;
20577 if (this.startDate !== -Infinity) {
20578 this.startDate = this.parseDate(this.startDate);
20581 this.updateNavArrows();
20584 setEndDate: function(endDate)
20586 this.endDate = endDate || Infinity;
20587 if (this.endDate !== Infinity) {
20588 this.endDate = this.parseDate(this.endDate);
20591 this.updateNavArrows();
20594 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
20596 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
20597 if (typeof(this.daysOfWeekDisabled) !== 'object') {
20598 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
20600 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
20601 return parseInt(d, 10);
20604 this.updateNavArrows();
20607 updateNavArrows: function()
20609 if(this.singleMode){
20613 var d = new Date(this.viewDate),
20614 year = d.getUTCFullYear(),
20615 month = d.getUTCMonth();
20617 Roo.each(this.picker().select('.prev', true).elements, function(v){
20619 switch (this.viewMode) {
20622 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
20628 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
20635 Roo.each(this.picker().select('.next', true).elements, function(v){
20637 switch (this.viewMode) {
20640 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
20646 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
20654 moveMonth: function(date, dir)
20659 var new_date = new Date(date.valueOf()),
20660 day = new_date.getUTCDate(),
20661 month = new_date.getUTCMonth(),
20662 mag = Math.abs(dir),
20664 dir = dir > 0 ? 1 : -1;
20667 // If going back one month, make sure month is not current month
20668 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
20670 return new_date.getUTCMonth() == month;
20672 // If going forward one month, make sure month is as expected
20673 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
20675 return new_date.getUTCMonth() != new_month;
20677 new_month = month + dir;
20678 new_date.setUTCMonth(new_month);
20679 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
20680 if (new_month < 0 || new_month > 11) {
20681 new_month = (new_month + 12) % 12;
20684 // For magnitudes >1, move one month at a time...
20685 for (var i=0; i<mag; i++) {
20686 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
20687 new_date = this.moveMonth(new_date, dir);
20689 // ...then reset the day, keeping it in the new month
20690 new_month = new_date.getUTCMonth();
20691 new_date.setUTCDate(day);
20693 return new_month != new_date.getUTCMonth();
20696 // Common date-resetting loop -- if date is beyond end of month, make it
20699 new_date.setUTCDate(--day);
20700 new_date.setUTCMonth(new_month);
20705 moveYear: function(date, dir)
20707 return this.moveMonth(date, dir*12);
20710 dateWithinRange: function(date)
20712 return date >= this.startDate && date <= this.endDate;
20718 this.picker().remove();
20721 validateValue : function(value)
20723 if(this.getVisibilityEl().hasClass('hidden')){
20727 if(value.length < 1) {
20728 if(this.allowBlank){
20734 if(value.length < this.minLength){
20737 if(value.length > this.maxLength){
20741 var vt = Roo.form.VTypes;
20742 if(!vt[this.vtype](value, this)){
20746 if(typeof this.validator == "function"){
20747 var msg = this.validator(value);
20753 if(this.regex && !this.regex.test(value)){
20757 if(typeof(this.parseDate(value)) == 'undefined'){
20761 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
20765 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
20775 this.date = this.viewDate = '';
20777 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
20782 Roo.apply(Roo.bootstrap.DateField, {
20793 html: '<i class="fa fa-arrow-left"/>'
20803 html: '<i class="fa fa-arrow-right"/>'
20845 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
20846 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
20847 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
20848 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20849 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
20862 navFnc: 'FullYear',
20867 navFnc: 'FullYear',
20872 Roo.apply(Roo.bootstrap.DateField, {
20876 cls: 'datepicker dropdown-menu roo-dynamic',
20880 cls: 'datepicker-days',
20884 cls: 'table-condensed',
20886 Roo.bootstrap.DateField.head,
20890 Roo.bootstrap.DateField.footer
20897 cls: 'datepicker-months',
20901 cls: 'table-condensed',
20903 Roo.bootstrap.DateField.head,
20904 Roo.bootstrap.DateField.content,
20905 Roo.bootstrap.DateField.footer
20912 cls: 'datepicker-years',
20916 cls: 'table-condensed',
20918 Roo.bootstrap.DateField.head,
20919 Roo.bootstrap.DateField.content,
20920 Roo.bootstrap.DateField.footer
20939 * @class Roo.bootstrap.TimeField
20940 * @extends Roo.bootstrap.Input
20941 * Bootstrap DateField class
20945 * Create a new TimeField
20946 * @param {Object} config The config object
20949 Roo.bootstrap.TimeField = function(config){
20950 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
20954 * Fires when this field show.
20955 * @param {Roo.bootstrap.DateField} thisthis
20956 * @param {Mixed} date The date value
20961 * Fires when this field hide.
20962 * @param {Roo.bootstrap.DateField} this
20963 * @param {Mixed} date The date value
20968 * Fires when select a date.
20969 * @param {Roo.bootstrap.DateField} this
20970 * @param {Mixed} date The date value
20976 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20979 * @cfg {String} format
20980 * The default time format string which can be overriden for localization support. The format must be
20981 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20985 onRender: function(ct, position)
20988 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20990 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20992 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20994 this.pop = this.picker().select('>.datepicker-time',true).first();
20995 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20997 this.picker().on('mousedown', this.onMousedown, this);
20998 this.picker().on('click', this.onClick, this);
21000 this.picker().addClass('datepicker-dropdown');
21005 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
21006 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
21007 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
21008 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
21009 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
21010 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
21014 fireKey: function(e){
21015 if (!this.picker().isVisible()){
21016 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21022 e.preventDefault();
21030 this.onTogglePeriod();
21033 this.onIncrementMinutes();
21036 this.onDecrementMinutes();
21045 onClick: function(e) {
21046 e.stopPropagation();
21047 e.preventDefault();
21050 picker : function()
21052 return this.el.select('.datepicker', true).first();
21055 fillTime: function()
21057 var time = this.pop.select('tbody', true).first();
21059 time.dom.innerHTML = '';
21074 cls: 'hours-up glyphicon glyphicon-chevron-up'
21094 cls: 'minutes-up glyphicon glyphicon-chevron-up'
21115 cls: 'timepicker-hour',
21130 cls: 'timepicker-minute',
21145 cls: 'btn btn-primary period',
21167 cls: 'hours-down glyphicon glyphicon-chevron-down'
21187 cls: 'minutes-down glyphicon glyphicon-chevron-down'
21205 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
21212 var hours = this.time.getHours();
21213 var minutes = this.time.getMinutes();
21226 hours = hours - 12;
21230 hours = '0' + hours;
21234 minutes = '0' + minutes;
21237 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
21238 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
21239 this.pop.select('button', true).first().dom.innerHTML = period;
21245 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
21247 var cls = ['bottom'];
21249 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
21256 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
21261 this.picker().addClass(cls.join('-'));
21265 Roo.each(cls, function(c){
21267 _this.picker().setTop(_this.inputEl().getHeight());
21271 _this.picker().setTop(0 - _this.picker().getHeight());
21276 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
21280 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
21287 onFocus : function()
21289 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
21293 onBlur : function()
21295 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
21301 this.picker().show();
21306 this.fireEvent('show', this, this.date);
21311 this.picker().hide();
21314 this.fireEvent('hide', this, this.date);
21317 setTime : function()
21320 this.setValue(this.time.format(this.format));
21322 this.fireEvent('select', this, this.date);
21327 onMousedown: function(e){
21328 e.stopPropagation();
21329 e.preventDefault();
21332 onIncrementHours: function()
21334 Roo.log('onIncrementHours');
21335 this.time = this.time.add(Date.HOUR, 1);
21340 onDecrementHours: function()
21342 Roo.log('onDecrementHours');
21343 this.time = this.time.add(Date.HOUR, -1);
21347 onIncrementMinutes: function()
21349 Roo.log('onIncrementMinutes');
21350 this.time = this.time.add(Date.MINUTE, 1);
21354 onDecrementMinutes: function()
21356 Roo.log('onDecrementMinutes');
21357 this.time = this.time.add(Date.MINUTE, -1);
21361 onTogglePeriod: function()
21363 Roo.log('onTogglePeriod');
21364 this.time = this.time.add(Date.HOUR, 12);
21371 Roo.apply(Roo.bootstrap.TimeField, {
21401 cls: 'btn btn-info ok',
21413 Roo.apply(Roo.bootstrap.TimeField, {
21417 cls: 'datepicker dropdown-menu',
21421 cls: 'datepicker-time',
21425 cls: 'table-condensed',
21427 Roo.bootstrap.TimeField.content,
21428 Roo.bootstrap.TimeField.footer
21447 * @class Roo.bootstrap.MonthField
21448 * @extends Roo.bootstrap.Input
21449 * Bootstrap MonthField class
21451 * @cfg {String} language default en
21454 * Create a new MonthField
21455 * @param {Object} config The config object
21458 Roo.bootstrap.MonthField = function(config){
21459 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
21464 * Fires when this field show.
21465 * @param {Roo.bootstrap.MonthField} this
21466 * @param {Mixed} date The date value
21471 * Fires when this field hide.
21472 * @param {Roo.bootstrap.MonthField} this
21473 * @param {Mixed} date The date value
21478 * Fires when select a date.
21479 * @param {Roo.bootstrap.MonthField} this
21480 * @param {String} oldvalue The old value
21481 * @param {String} newvalue The new value
21487 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
21489 onRender: function(ct, position)
21492 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
21494 this.language = this.language || 'en';
21495 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
21496 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
21498 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
21499 this.isInline = false;
21500 this.isInput = true;
21501 this.component = this.el.select('.add-on', true).first() || false;
21502 this.component = (this.component && this.component.length === 0) ? false : this.component;
21503 this.hasInput = this.component && this.inputEL().length;
21505 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
21507 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21509 this.picker().on('mousedown', this.onMousedown, this);
21510 this.picker().on('click', this.onClick, this);
21512 this.picker().addClass('datepicker-dropdown');
21514 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
21515 v.setStyle('width', '189px');
21522 if(this.isInline) {
21528 setValue: function(v, suppressEvent)
21530 var o = this.getValue();
21532 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
21536 if(suppressEvent !== true){
21537 this.fireEvent('select', this, o, v);
21542 getValue: function()
21547 onClick: function(e)
21549 e.stopPropagation();
21550 e.preventDefault();
21552 var target = e.getTarget();
21554 if(target.nodeName.toLowerCase() === 'i'){
21555 target = Roo.get(target).dom.parentNode;
21558 var nodeName = target.nodeName;
21559 var className = target.className;
21560 var html = target.innerHTML;
21562 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
21566 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
21568 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21574 picker : function()
21576 return this.pickerEl;
21579 fillMonths: function()
21582 var months = this.picker().select('>.datepicker-months td', true).first();
21584 months.dom.innerHTML = '';
21590 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
21593 months.createChild(month);
21602 if(typeof(this.vIndex) == 'undefined' && this.value.length){
21603 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
21606 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
21607 e.removeClass('active');
21609 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
21610 e.addClass('active');
21617 if(this.isInline) {
21621 this.picker().removeClass(['bottom', 'top']);
21623 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
21625 * place to the top of element!
21629 this.picker().addClass('top');
21630 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
21635 this.picker().addClass('bottom');
21637 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
21640 onFocus : function()
21642 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
21646 onBlur : function()
21648 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
21650 var d = this.inputEl().getValue();
21659 this.picker().show();
21660 this.picker().select('>.datepicker-months', true).first().show();
21664 this.fireEvent('show', this, this.date);
21669 if(this.isInline) {
21672 this.picker().hide();
21673 this.fireEvent('hide', this, this.date);
21677 onMousedown: function(e)
21679 e.stopPropagation();
21680 e.preventDefault();
21685 Roo.bootstrap.MonthField.superclass.keyup.call(this);
21689 fireKey: function(e)
21691 if (!this.picker().isVisible()){
21692 if (e.keyCode == 27) {// allow escape to hide and re-show picker
21703 e.preventDefault();
21707 dir = e.keyCode == 37 ? -1 : 1;
21709 this.vIndex = this.vIndex + dir;
21711 if(this.vIndex < 0){
21715 if(this.vIndex > 11){
21719 if(isNaN(this.vIndex)){
21723 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21729 dir = e.keyCode == 38 ? -1 : 1;
21731 this.vIndex = this.vIndex + dir * 4;
21733 if(this.vIndex < 0){
21737 if(this.vIndex > 11){
21741 if(isNaN(this.vIndex)){
21745 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21750 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
21751 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21755 e.preventDefault();
21758 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
21759 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21775 this.picker().remove();
21780 Roo.apply(Roo.bootstrap.MonthField, {
21799 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
21800 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
21805 Roo.apply(Roo.bootstrap.MonthField, {
21809 cls: 'datepicker dropdown-menu roo-dynamic',
21813 cls: 'datepicker-months',
21817 cls: 'table-condensed',
21819 Roo.bootstrap.DateField.content
21839 * @class Roo.bootstrap.CheckBox
21840 * @extends Roo.bootstrap.Input
21841 * Bootstrap CheckBox class
21843 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
21844 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
21845 * @cfg {String} boxLabel The text that appears beside the checkbox
21846 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
21847 * @cfg {Boolean} checked initnal the element
21848 * @cfg {Boolean} inline inline the element (default false)
21849 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
21850 * @cfg {String} tooltip label tooltip
21853 * Create a new CheckBox
21854 * @param {Object} config The config object
21857 Roo.bootstrap.CheckBox = function(config){
21858 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
21863 * Fires when the element is checked or unchecked.
21864 * @param {Roo.bootstrap.CheckBox} this This input
21865 * @param {Boolean} checked The new checked value
21870 * Fires when the element is click.
21871 * @param {Roo.bootstrap.CheckBox} this This input
21878 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
21880 inputType: 'checkbox',
21889 // checkbox success does not make any sense really..
21894 getAutoCreate : function()
21896 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
21902 cfg.cls = 'form-group form-check ' + this.inputType; //input-group
21905 cfg.cls += ' ' + this.inputType + '-inline form-check-inline';
21911 type : this.inputType,
21912 value : this.inputValue,
21913 cls : 'roo-' + this.inputType, //'form-box',
21914 placeholder : this.placeholder || ''
21918 if(this.inputType != 'radio'){
21922 cls : 'roo-hidden-value',
21923 value : this.checked ? this.inputValue : this.valueOff
21928 if (this.weight) { // Validity check?
21929 cfg.cls += " " + this.inputType + "-" + this.weight;
21932 if (this.disabled) {
21933 input.disabled=true;
21937 input.checked = this.checked;
21942 input.name = this.name;
21944 if(this.inputType != 'radio'){
21945 hidden.name = this.name;
21946 input.name = '_hidden_' + this.name;
21951 input.cls += ' input-' + this.size;
21956 ['xs','sm','md','lg'].map(function(size){
21957 if (settings[size]) {
21958 cfg.cls += ' col-' + size + '-' + settings[size];
21962 var inputblock = input;
21964 if (this.before || this.after) {
21967 cls : 'input-group',
21972 inputblock.cn.push({
21974 cls : 'input-group-addon',
21979 inputblock.cn.push(input);
21981 if(this.inputType != 'radio'){
21982 inputblock.cn.push(hidden);
21986 inputblock.cn.push({
21988 cls : 'input-group-addon',
21994 var boxLabelCfg = false;
22000 //'for': id, // box label is handled by onclick - so no for...
22002 html: this.boxLabel
22005 boxLabelCfg.tooltip = this.tooltip;
22011 if (align ==='left' && this.fieldLabel.length) {
22012 // Roo.log("left and has label");
22017 cls : 'control-label',
22018 html : this.fieldLabel
22029 cfg.cn[1].cn.push(boxLabelCfg);
22032 if(this.labelWidth > 12){
22033 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
22036 if(this.labelWidth < 13 && this.labelmd == 0){
22037 this.labelmd = this.labelWidth;
22040 if(this.labellg > 0){
22041 cfg.cn[0].cls += ' col-lg-' + this.labellg;
22042 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
22045 if(this.labelmd > 0){
22046 cfg.cn[0].cls += ' col-md-' + this.labelmd;
22047 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
22050 if(this.labelsm > 0){
22051 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
22052 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
22055 if(this.labelxs > 0){
22056 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
22057 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
22060 } else if ( this.fieldLabel.length) {
22061 // Roo.log(" label");
22065 tag: this.boxLabel ? 'span' : 'label',
22067 cls: 'control-label box-input-label',
22068 //cls : 'input-group-addon',
22069 html : this.fieldLabel
22076 cfg.cn.push(boxLabelCfg);
22081 // Roo.log(" no label && no align");
22082 cfg.cn = [ inputblock ] ;
22084 cfg.cn.push(boxLabelCfg);
22092 if(this.inputType != 'radio'){
22093 cfg.cn.push(hidden);
22101 * return the real input element.
22103 inputEl: function ()
22105 return this.el.select('input.roo-' + this.inputType,true).first();
22107 hiddenEl: function ()
22109 return this.el.select('input.roo-hidden-value',true).first();
22112 labelEl: function()
22114 return this.el.select('label.control-label',true).first();
22116 /* depricated... */
22120 return this.labelEl();
22123 boxLabelEl: function()
22125 return this.el.select('label.box-label',true).first();
22128 initEvents : function()
22130 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
22132 this.inputEl().on('click', this.onClick, this);
22134 if (this.boxLabel) {
22135 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
22138 this.startValue = this.getValue();
22141 Roo.bootstrap.CheckBox.register(this);
22145 onClick : function(e)
22147 if(this.fireEvent('click', this, e) !== false){
22148 this.setChecked(!this.checked);
22153 setChecked : function(state,suppressEvent)
22155 this.startValue = this.getValue();
22157 if(this.inputType == 'radio'){
22159 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22160 e.dom.checked = false;
22163 this.inputEl().dom.checked = true;
22165 this.inputEl().dom.value = this.inputValue;
22167 if(suppressEvent !== true){
22168 this.fireEvent('check', this, true);
22176 this.checked = state;
22178 this.inputEl().dom.checked = state;
22181 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
22183 if(suppressEvent !== true){
22184 this.fireEvent('check', this, state);
22190 getValue : function()
22192 if(this.inputType == 'radio'){
22193 return this.getGroupValue();
22196 return this.hiddenEl().dom.value;
22200 getGroupValue : function()
22202 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
22206 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
22209 setValue : function(v,suppressEvent)
22211 if(this.inputType == 'radio'){
22212 this.setGroupValue(v, suppressEvent);
22216 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
22221 setGroupValue : function(v, suppressEvent)
22223 this.startValue = this.getValue();
22225 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22226 e.dom.checked = false;
22228 if(e.dom.value == v){
22229 e.dom.checked = true;
22233 if(suppressEvent !== true){
22234 this.fireEvent('check', this, true);
22242 validate : function()
22244 if(this.getVisibilityEl().hasClass('hidden')){
22250 (this.inputType == 'radio' && this.validateRadio()) ||
22251 (this.inputType == 'checkbox' && this.validateCheckbox())
22257 this.markInvalid();
22261 validateRadio : function()
22263 if(this.getVisibilityEl().hasClass('hidden')){
22267 if(this.allowBlank){
22273 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22274 if(!e.dom.checked){
22286 validateCheckbox : function()
22289 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
22290 //return (this.getValue() == this.inputValue) ? true : false;
22293 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22301 for(var i in group){
22302 if(group[i].el.isVisible(true)){
22310 for(var i in group){
22315 r = (group[i].getValue() == group[i].inputValue) ? true : false;
22322 * Mark this field as valid
22324 markValid : function()
22328 this.fireEvent('valid', this);
22330 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22333 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
22340 if(this.inputType == 'radio'){
22341 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22342 var fg = e.findParent('.form-group', false, true);
22343 if (Roo.bootstrap.version == 3) {
22344 fg.removeClass([_this.invalidClass, _this.validClass]);
22345 fg.addClass(_this.validClass);
22347 fg.removeClass(['is-valid', 'is-invalid']);
22348 fg.addClass('is-valid');
22356 var fg = this.el.findParent('.form-group', false, true);
22357 if (Roo.bootstrap.version == 3) {
22358 fg.removeClass([this.invalidClass, this.validClass]);
22359 fg.addClass(this.validClass);
22361 fg.removeClass(['is-valid', 'is-invalid']);
22362 fg.addClass('is-valid');
22367 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22373 for(var i in group){
22374 var fg = group[i].el.findParent('.form-group', false, true);
22375 if (Roo.bootstrap.version == 3) {
22376 fg.removeClass([this.invalidClass, this.validClass]);
22377 fg.addClass(this.validClass);
22379 fg.removeClass(['is-valid', 'is-invalid']);
22380 fg.addClass('is-valid');
22386 * Mark this field as invalid
22387 * @param {String} msg The validation message
22389 markInvalid : function(msg)
22391 if(this.allowBlank){
22397 this.fireEvent('invalid', this, msg);
22399 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22402 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
22406 label.markInvalid();
22409 if(this.inputType == 'radio'){
22411 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22412 var fg = e.findParent('.form-group', false, true);
22413 if (Roo.bootstrap.version == 3) {
22414 fg.removeClass([_this.invalidClass, _this.validClass]);
22415 fg.addClass(_this.invalidClass);
22417 fg.removeClass(['is-invalid', 'is-valid']);
22418 fg.addClass('is-invalid');
22426 var fg = this.el.findParent('.form-group', false, true);
22427 if (Roo.bootstrap.version == 3) {
22428 fg.removeClass([_this.invalidClass, _this.validClass]);
22429 fg.addClass(_this.invalidClass);
22431 fg.removeClass(['is-invalid', 'is-valid']);
22432 fg.addClass('is-invalid');
22437 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22443 for(var i in group){
22444 var fg = group[i].el.findParent('.form-group', false, true);
22445 if (Roo.bootstrap.version == 3) {
22446 fg.removeClass([_this.invalidClass, _this.validClass]);
22447 fg.addClass(_this.invalidClass);
22449 fg.removeClass(['is-invalid', 'is-valid']);
22450 fg.addClass('is-invalid');
22456 clearInvalid : function()
22458 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
22460 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
22462 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22464 if (label && label.iconEl) {
22465 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
22466 label.iconEl.removeClass(['is-invalid', 'is-valid']);
22470 disable : function()
22472 if(this.inputType != 'radio'){
22473 Roo.bootstrap.CheckBox.superclass.disable.call(this);
22480 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22481 _this.getActionEl().addClass(this.disabledClass);
22482 e.dom.disabled = true;
22486 this.disabled = true;
22487 this.fireEvent("disable", this);
22491 enable : function()
22493 if(this.inputType != 'radio'){
22494 Roo.bootstrap.CheckBox.superclass.enable.call(this);
22501 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22502 _this.getActionEl().removeClass(this.disabledClass);
22503 e.dom.disabled = false;
22507 this.disabled = false;
22508 this.fireEvent("enable", this);
22512 setBoxLabel : function(v)
22517 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
22523 Roo.apply(Roo.bootstrap.CheckBox, {
22528 * register a CheckBox Group
22529 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
22531 register : function(checkbox)
22533 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
22534 this.groups[checkbox.groupId] = {};
22537 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
22541 this.groups[checkbox.groupId][checkbox.name] = checkbox;
22545 * fetch a CheckBox Group based on the group ID
22546 * @param {string} the group ID
22547 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
22549 get: function(groupId) {
22550 if (typeof(this.groups[groupId]) == 'undefined') {
22554 return this.groups[groupId] ;
22567 * @class Roo.bootstrap.Radio
22568 * @extends Roo.bootstrap.Component
22569 * Bootstrap Radio class
22570 * @cfg {String} boxLabel - the label associated
22571 * @cfg {String} value - the value of radio
22574 * Create a new Radio
22575 * @param {Object} config The config object
22577 Roo.bootstrap.Radio = function(config){
22578 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
22582 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
22588 getAutoCreate : function()
22592 cls : 'form-group radio',
22597 html : this.boxLabel
22605 initEvents : function()
22607 this.parent().register(this);
22609 this.el.on('click', this.onClick, this);
22613 onClick : function(e)
22615 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
22616 this.setChecked(true);
22620 setChecked : function(state, suppressEvent)
22622 this.parent().setValue(this.value, suppressEvent);
22626 setBoxLabel : function(v)
22631 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
22646 * @class Roo.bootstrap.SecurePass
22647 * @extends Roo.bootstrap.Input
22648 * Bootstrap SecurePass class
22652 * Create a new SecurePass
22653 * @param {Object} config The config object
22656 Roo.bootstrap.SecurePass = function (config) {
22657 // these go here, so the translation tool can replace them..
22659 PwdEmpty: "Please type a password, and then retype it to confirm.",
22660 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
22661 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
22662 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
22663 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
22664 FNInPwd: "Your password can't contain your first name. Please type a different password.",
22665 LNInPwd: "Your password can't contain your last name. Please type a different password.",
22666 TooWeak: "Your password is Too Weak."
22668 this.meterLabel = "Password strength:";
22669 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
22670 this.meterClass = [
22671 "roo-password-meter-tooweak",
22672 "roo-password-meter-weak",
22673 "roo-password-meter-medium",
22674 "roo-password-meter-strong",
22675 "roo-password-meter-grey"
22680 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
22683 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
22685 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
22687 * PwdEmpty: "Please type a password, and then retype it to confirm.",
22688 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
22689 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
22690 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
22691 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
22692 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
22693 * LNInPwd: "Your password can't contain your last name. Please type a different password."
22703 * @cfg {String/Object} Label for the strength meter (defaults to
22704 * 'Password strength:')
22709 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
22710 * ['Weak', 'Medium', 'Strong'])
22713 pwdStrengths: false,
22726 initEvents: function ()
22728 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
22730 if (this.el.is('input[type=password]') && Roo.isSafari) {
22731 this.el.on('keydown', this.SafariOnKeyDown, this);
22734 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
22737 onRender: function (ct, position)
22739 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
22740 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
22741 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
22743 this.trigger.createChild({
22748 cls: 'roo-password-meter-grey col-xs-12',
22751 //width: this.meterWidth + 'px'
22755 cls: 'roo-password-meter-text'
22761 if (this.hideTrigger) {
22762 this.trigger.setDisplayed(false);
22764 this.setSize(this.width || '', this.height || '');
22767 onDestroy: function ()
22769 if (this.trigger) {
22770 this.trigger.removeAllListeners();
22771 this.trigger.remove();
22774 this.wrap.remove();
22776 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
22779 checkStrength: function ()
22781 var pwd = this.inputEl().getValue();
22782 if (pwd == this._lastPwd) {
22787 if (this.ClientSideStrongPassword(pwd)) {
22789 } else if (this.ClientSideMediumPassword(pwd)) {
22791 } else if (this.ClientSideWeakPassword(pwd)) {
22797 Roo.log('strength1: ' + strength);
22799 //var pm = this.trigger.child('div/div/div').dom;
22800 var pm = this.trigger.child('div/div');
22801 pm.removeClass(this.meterClass);
22802 pm.addClass(this.meterClass[strength]);
22805 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22807 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
22809 this._lastPwd = pwd;
22813 Roo.bootstrap.SecurePass.superclass.reset.call(this);
22815 this._lastPwd = '';
22817 var pm = this.trigger.child('div/div');
22818 pm.removeClass(this.meterClass);
22819 pm.addClass('roo-password-meter-grey');
22822 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22825 this.inputEl().dom.type='password';
22828 validateValue: function (value)
22831 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
22834 if (value.length == 0) {
22835 if (this.allowBlank) {
22836 this.clearInvalid();
22840 this.markInvalid(this.errors.PwdEmpty);
22841 this.errorMsg = this.errors.PwdEmpty;
22849 if ('[\x21-\x7e]*'.match(value)) {
22850 this.markInvalid(this.errors.PwdBadChar);
22851 this.errorMsg = this.errors.PwdBadChar;
22854 if (value.length < 6) {
22855 this.markInvalid(this.errors.PwdShort);
22856 this.errorMsg = this.errors.PwdShort;
22859 if (value.length > 16) {
22860 this.markInvalid(this.errors.PwdLong);
22861 this.errorMsg = this.errors.PwdLong;
22865 if (this.ClientSideStrongPassword(value)) {
22867 } else if (this.ClientSideMediumPassword(value)) {
22869 } else if (this.ClientSideWeakPassword(value)) {
22876 if (strength < 2) {
22877 //this.markInvalid(this.errors.TooWeak);
22878 this.errorMsg = this.errors.TooWeak;
22883 console.log('strength2: ' + strength);
22885 //var pm = this.trigger.child('div/div/div').dom;
22887 var pm = this.trigger.child('div/div');
22888 pm.removeClass(this.meterClass);
22889 pm.addClass(this.meterClass[strength]);
22891 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22893 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
22895 this.errorMsg = '';
22899 CharacterSetChecks: function (type)
22902 this.fResult = false;
22905 isctype: function (character, type)
22908 case this.kCapitalLetter:
22909 if (character >= 'A' && character <= 'Z') {
22914 case this.kSmallLetter:
22915 if (character >= 'a' && character <= 'z') {
22921 if (character >= '0' && character <= '9') {
22926 case this.kPunctuation:
22927 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
22938 IsLongEnough: function (pwd, size)
22940 return !(pwd == null || isNaN(size) || pwd.length < size);
22943 SpansEnoughCharacterSets: function (word, nb)
22945 if (!this.IsLongEnough(word, nb))
22950 var characterSetChecks = new Array(
22951 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
22952 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
22955 for (var index = 0; index < word.length; ++index) {
22956 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
22957 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
22958 characterSetChecks[nCharSet].fResult = true;
22965 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
22966 if (characterSetChecks[nCharSet].fResult) {
22971 if (nCharSets < nb) {
22977 ClientSideStrongPassword: function (pwd)
22979 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
22982 ClientSideMediumPassword: function (pwd)
22984 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22987 ClientSideWeakPassword: function (pwd)
22989 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22992 })//<script type="text/javascript">
22995 * Based Ext JS Library 1.1.1
22996 * Copyright(c) 2006-2007, Ext JS, LLC.
23002 * @class Roo.HtmlEditorCore
23003 * @extends Roo.Component
23004 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
23006 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23009 Roo.HtmlEditorCore = function(config){
23012 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
23017 * @event initialize
23018 * Fires when the editor is fully initialized (including the iframe)
23019 * @param {Roo.HtmlEditorCore} this
23024 * Fires when the editor is first receives the focus. Any insertion must wait
23025 * until after this event.
23026 * @param {Roo.HtmlEditorCore} this
23030 * @event beforesync
23031 * Fires before the textarea is updated with content from the editor iframe. Return false
23032 * to cancel the sync.
23033 * @param {Roo.HtmlEditorCore} this
23034 * @param {String} html
23038 * @event beforepush
23039 * Fires before the iframe editor is updated with content from the textarea. Return false
23040 * to cancel the push.
23041 * @param {Roo.HtmlEditorCore} this
23042 * @param {String} html
23047 * Fires when the textarea is updated with content from the editor iframe.
23048 * @param {Roo.HtmlEditorCore} this
23049 * @param {String} html
23054 * Fires when the iframe editor is updated with content from the textarea.
23055 * @param {Roo.HtmlEditorCore} this
23056 * @param {String} html
23061 * @event editorevent
23062 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23063 * @param {Roo.HtmlEditorCore} this
23069 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
23071 // defaults : white / black...
23072 this.applyBlacklists();
23079 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
23083 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
23089 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23094 * @cfg {Number} height (in pixels)
23098 * @cfg {Number} width (in pixels)
23103 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23106 stylesheets: false,
23111 // private properties
23112 validationEvent : false,
23114 initialized : false,
23116 sourceEditMode : false,
23117 onFocus : Roo.emptyFn,
23119 hideMode:'offsets',
23123 // blacklist + whitelisted elements..
23130 * Protected method that will not generally be called directly. It
23131 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23132 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23134 getDocMarkup : function(){
23138 // inherit styels from page...??
23139 if (this.stylesheets === false) {
23141 Roo.get(document.head).select('style').each(function(node) {
23142 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23145 Roo.get(document.head).select('link').each(function(node) {
23146 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23149 } else if (!this.stylesheets.length) {
23151 st = '<style type="text/css">' +
23152 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23155 st = '<style type="text/css">' +
23160 st += '<style type="text/css">' +
23161 'IMG { cursor: pointer } ' +
23164 var cls = 'roo-htmleditor-body';
23166 if(this.bodyCls.length){
23167 cls += ' ' + this.bodyCls;
23170 return '<html><head>' + st +
23171 //<style type="text/css">' +
23172 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23174 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
23178 onRender : function(ct, position)
23181 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
23182 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
23185 this.el.dom.style.border = '0 none';
23186 this.el.dom.setAttribute('tabIndex', -1);
23187 this.el.addClass('x-hidden hide');
23191 if(Roo.isIE){ // fix IE 1px bogus margin
23192 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
23196 this.frameId = Roo.id();
23200 var iframe = this.owner.wrap.createChild({
23202 cls: 'form-control', // bootstrap..
23204 name: this.frameId,
23205 frameBorder : 'no',
23206 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
23211 this.iframe = iframe.dom;
23213 this.assignDocWin();
23215 this.doc.designMode = 'on';
23218 this.doc.write(this.getDocMarkup());
23222 var task = { // must defer to wait for browser to be ready
23224 //console.log("run task?" + this.doc.readyState);
23225 this.assignDocWin();
23226 if(this.doc.body || this.doc.readyState == 'complete'){
23228 this.doc.designMode="on";
23232 Roo.TaskMgr.stop(task);
23233 this.initEditor.defer(10, this);
23240 Roo.TaskMgr.start(task);
23245 onResize : function(w, h)
23247 Roo.log('resize: ' +w + ',' + h );
23248 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
23252 if(typeof w == 'number'){
23254 this.iframe.style.width = w + 'px';
23256 if(typeof h == 'number'){
23258 this.iframe.style.height = h + 'px';
23260 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
23267 * Toggles the editor between standard and source edit mode.
23268 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23270 toggleSourceEdit : function(sourceEditMode){
23272 this.sourceEditMode = sourceEditMode === true;
23274 if(this.sourceEditMode){
23276 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
23279 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
23280 //this.iframe.className = '';
23283 //this.setSize(this.owner.wrap.getSize());
23284 //this.fireEvent('editmodechange', this, this.sourceEditMode);
23291 * Protected method that will not generally be called directly. If you need/want
23292 * custom HTML cleanup, this is the method you should override.
23293 * @param {String} html The HTML to be cleaned
23294 * return {String} The cleaned HTML
23296 cleanHtml : function(html){
23297 html = String(html);
23298 if(html.length > 5){
23299 if(Roo.isSafari){ // strip safari nonsense
23300 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
23303 if(html == ' '){
23310 * HTML Editor -> Textarea
23311 * Protected method that will not generally be called directly. Syncs the contents
23312 * of the editor iframe with the textarea.
23314 syncValue : function(){
23315 if(this.initialized){
23316 var bd = (this.doc.body || this.doc.documentElement);
23317 //this.cleanUpPaste(); -- this is done else where and causes havoc..
23318 var html = bd.innerHTML;
23320 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
23321 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
23323 html = '<div style="'+m[0]+'">' + html + '</div>';
23326 html = this.cleanHtml(html);
23327 // fix up the special chars.. normaly like back quotes in word...
23328 // however we do not want to do this with chinese..
23329 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
23331 var cc = match.charCodeAt();
23333 // Get the character value, handling surrogate pairs
23334 if (match.length == 2) {
23335 // It's a surrogate pair, calculate the Unicode code point
23336 var high = match.charCodeAt(0) - 0xD800;
23337 var low = match.charCodeAt(1) - 0xDC00;
23338 cc = (high * 0x400) + low + 0x10000;
23340 (cc >= 0x4E00 && cc < 0xA000 ) ||
23341 (cc >= 0x3400 && cc < 0x4E00 ) ||
23342 (cc >= 0xf900 && cc < 0xfb00 )
23347 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
23348 return "&#" + cc + ";";
23355 if(this.owner.fireEvent('beforesync', this, html) !== false){
23356 this.el.dom.value = html;
23357 this.owner.fireEvent('sync', this, html);
23363 * Protected method that will not generally be called directly. Pushes the value of the textarea
23364 * into the iframe editor.
23366 pushValue : function(){
23367 if(this.initialized){
23368 var v = this.el.dom.value.trim();
23370 // if(v.length < 1){
23374 if(this.owner.fireEvent('beforepush', this, v) !== false){
23375 var d = (this.doc.body || this.doc.documentElement);
23377 this.cleanUpPaste();
23378 this.el.dom.value = d.innerHTML;
23379 this.owner.fireEvent('push', this, v);
23385 deferFocus : function(){
23386 this.focus.defer(10, this);
23390 focus : function(){
23391 if(this.win && !this.sourceEditMode){
23398 assignDocWin: function()
23400 var iframe = this.iframe;
23403 this.doc = iframe.contentWindow.document;
23404 this.win = iframe.contentWindow;
23406 // if (!Roo.get(this.frameId)) {
23409 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
23410 // this.win = Roo.get(this.frameId).dom.contentWindow;
23412 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
23416 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
23417 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
23422 initEditor : function(){
23423 //console.log("INIT EDITOR");
23424 this.assignDocWin();
23428 this.doc.designMode="on";
23430 this.doc.write(this.getDocMarkup());
23433 var dbody = (this.doc.body || this.doc.documentElement);
23434 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
23435 // this copies styles from the containing element into thsi one..
23436 // not sure why we need all of this..
23437 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
23439 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
23440 //ss['background-attachment'] = 'fixed'; // w3c
23441 dbody.bgProperties = 'fixed'; // ie
23442 //Roo.DomHelper.applyStyles(dbody, ss);
23443 Roo.EventManager.on(this.doc, {
23444 //'mousedown': this.onEditorEvent,
23445 'mouseup': this.onEditorEvent,
23446 'dblclick': this.onEditorEvent,
23447 'click': this.onEditorEvent,
23448 'keyup': this.onEditorEvent,
23453 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
23455 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
23456 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
23458 this.initialized = true;
23460 this.owner.fireEvent('initialize', this);
23465 onDestroy : function(){
23471 //for (var i =0; i < this.toolbars.length;i++) {
23472 // // fixme - ask toolbars for heights?
23473 // this.toolbars[i].onDestroy();
23476 //this.wrap.dom.innerHTML = '';
23477 //this.wrap.remove();
23482 onFirstFocus : function(){
23484 this.assignDocWin();
23487 this.activated = true;
23490 if(Roo.isGecko){ // prevent silly gecko errors
23492 var s = this.win.getSelection();
23493 if(!s.focusNode || s.focusNode.nodeType != 3){
23494 var r = s.getRangeAt(0);
23495 r.selectNodeContents((this.doc.body || this.doc.documentElement));
23500 this.execCmd('useCSS', true);
23501 this.execCmd('styleWithCSS', false);
23504 this.owner.fireEvent('activate', this);
23508 adjustFont: function(btn){
23509 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
23510 //if(Roo.isSafari){ // safari
23513 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
23514 if(Roo.isSafari){ // safari
23515 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
23516 v = (v < 10) ? 10 : v;
23517 v = (v > 48) ? 48 : v;
23518 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
23523 v = Math.max(1, v+adjust);
23525 this.execCmd('FontSize', v );
23528 onEditorEvent : function(e)
23530 this.owner.fireEvent('editorevent', this, e);
23531 // this.updateToolbar();
23532 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
23535 insertTag : function(tg)
23537 // could be a bit smarter... -> wrap the current selected tRoo..
23538 if (tg.toLowerCase() == 'span' ||
23539 tg.toLowerCase() == 'code' ||
23540 tg.toLowerCase() == 'sup' ||
23541 tg.toLowerCase() == 'sub'
23544 range = this.createRange(this.getSelection());
23545 var wrappingNode = this.doc.createElement(tg.toLowerCase());
23546 wrappingNode.appendChild(range.extractContents());
23547 range.insertNode(wrappingNode);
23554 this.execCmd("formatblock", tg);
23558 insertText : function(txt)
23562 var range = this.createRange();
23563 range.deleteContents();
23564 //alert(Sender.getAttribute('label'));
23566 range.insertNode(this.doc.createTextNode(txt));
23572 * Executes a Midas editor command on the editor document and performs necessary focus and
23573 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
23574 * @param {String} cmd The Midas command
23575 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
23577 relayCmd : function(cmd, value){
23579 this.execCmd(cmd, value);
23580 this.owner.fireEvent('editorevent', this);
23581 //this.updateToolbar();
23582 this.owner.deferFocus();
23586 * Executes a Midas editor command directly on the editor document.
23587 * For visual commands, you should use {@link #relayCmd} instead.
23588 * <b>This should only be called after the editor is initialized.</b>
23589 * @param {String} cmd The Midas command
23590 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
23592 execCmd : function(cmd, value){
23593 this.doc.execCommand(cmd, false, value === undefined ? null : value);
23600 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
23602 * @param {String} text | dom node..
23604 insertAtCursor : function(text)
23607 if(!this.activated){
23613 var r = this.doc.selection.createRange();
23624 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
23628 // from jquery ui (MIT licenced)
23630 var win = this.win;
23632 if (win.getSelection && win.getSelection().getRangeAt) {
23633 range = win.getSelection().getRangeAt(0);
23634 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
23635 range.insertNode(node);
23636 } else if (win.document.selection && win.document.selection.createRange) {
23637 // no firefox support
23638 var txt = typeof(text) == 'string' ? text : text.outerHTML;
23639 win.document.selection.createRange().pasteHTML(txt);
23641 // no firefox support
23642 var txt = typeof(text) == 'string' ? text : text.outerHTML;
23643 this.execCmd('InsertHTML', txt);
23652 mozKeyPress : function(e){
23654 var c = e.getCharCode(), cmd;
23657 c = String.fromCharCode(c).toLowerCase();
23671 this.cleanUpPaste.defer(100, this);
23679 e.preventDefault();
23687 fixKeys : function(){ // load time branching for fastest keydown performance
23689 return function(e){
23690 var k = e.getKey(), r;
23693 r = this.doc.selection.createRange();
23696 r.pasteHTML('    ');
23703 r = this.doc.selection.createRange();
23705 var target = r.parentElement();
23706 if(!target || target.tagName.toLowerCase() != 'li'){
23708 r.pasteHTML('<br />');
23714 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23715 this.cleanUpPaste.defer(100, this);
23721 }else if(Roo.isOpera){
23722 return function(e){
23723 var k = e.getKey();
23727 this.execCmd('InsertHTML','    ');
23730 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23731 this.cleanUpPaste.defer(100, this);
23736 }else if(Roo.isSafari){
23737 return function(e){
23738 var k = e.getKey();
23742 this.execCmd('InsertText','\t');
23746 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23747 this.cleanUpPaste.defer(100, this);
23755 getAllAncestors: function()
23757 var p = this.getSelectedNode();
23760 a.push(p); // push blank onto stack..
23761 p = this.getParentElement();
23765 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
23769 a.push(this.doc.body);
23773 lastSelNode : false,
23776 getSelection : function()
23778 this.assignDocWin();
23779 return Roo.isIE ? this.doc.selection : this.win.getSelection();
23782 getSelectedNode: function()
23784 // this may only work on Gecko!!!
23786 // should we cache this!!!!
23791 var range = this.createRange(this.getSelection()).cloneRange();
23794 var parent = range.parentElement();
23796 var testRange = range.duplicate();
23797 testRange.moveToElementText(parent);
23798 if (testRange.inRange(range)) {
23801 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
23804 parent = parent.parentElement;
23809 // is ancestor a text element.
23810 var ac = range.commonAncestorContainer;
23811 if (ac.nodeType == 3) {
23812 ac = ac.parentNode;
23815 var ar = ac.childNodes;
23818 var other_nodes = [];
23819 var has_other_nodes = false;
23820 for (var i=0;i<ar.length;i++) {
23821 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
23824 // fullly contained node.
23826 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
23831 // probably selected..
23832 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
23833 other_nodes.push(ar[i]);
23837 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
23842 has_other_nodes = true;
23844 if (!nodes.length && other_nodes.length) {
23845 nodes= other_nodes;
23847 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
23853 createRange: function(sel)
23855 // this has strange effects when using with
23856 // top toolbar - not sure if it's a great idea.
23857 //this.editor.contentWindow.focus();
23858 if (typeof sel != "undefined") {
23860 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
23862 return this.doc.createRange();
23865 return this.doc.createRange();
23868 getParentElement: function()
23871 this.assignDocWin();
23872 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
23874 var range = this.createRange(sel);
23877 var p = range.commonAncestorContainer;
23878 while (p.nodeType == 3) { // text node
23889 * Range intersection.. the hard stuff...
23893 * [ -- selected range --- ]
23897 * if end is before start or hits it. fail.
23898 * if start is after end or hits it fail.
23900 * if either hits (but other is outside. - then it's not
23906 // @see http://www.thismuchiknow.co.uk/?p=64.
23907 rangeIntersectsNode : function(range, node)
23909 var nodeRange = node.ownerDocument.createRange();
23911 nodeRange.selectNode(node);
23913 nodeRange.selectNodeContents(node);
23916 var rangeStartRange = range.cloneRange();
23917 rangeStartRange.collapse(true);
23919 var rangeEndRange = range.cloneRange();
23920 rangeEndRange.collapse(false);
23922 var nodeStartRange = nodeRange.cloneRange();
23923 nodeStartRange.collapse(true);
23925 var nodeEndRange = nodeRange.cloneRange();
23926 nodeEndRange.collapse(false);
23928 return rangeStartRange.compareBoundaryPoints(
23929 Range.START_TO_START, nodeEndRange) == -1 &&
23930 rangeEndRange.compareBoundaryPoints(
23931 Range.START_TO_START, nodeStartRange) == 1;
23935 rangeCompareNode : function(range, node)
23937 var nodeRange = node.ownerDocument.createRange();
23939 nodeRange.selectNode(node);
23941 nodeRange.selectNodeContents(node);
23945 range.collapse(true);
23947 nodeRange.collapse(true);
23949 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
23950 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
23952 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
23954 var nodeIsBefore = ss == 1;
23955 var nodeIsAfter = ee == -1;
23957 if (nodeIsBefore && nodeIsAfter) {
23960 if (!nodeIsBefore && nodeIsAfter) {
23961 return 1; //right trailed.
23964 if (nodeIsBefore && !nodeIsAfter) {
23965 return 2; // left trailed.
23971 // private? - in a new class?
23972 cleanUpPaste : function()
23974 // cleans up the whole document..
23975 Roo.log('cleanuppaste');
23977 this.cleanUpChildren(this.doc.body);
23978 var clean = this.cleanWordChars(this.doc.body.innerHTML);
23979 if (clean != this.doc.body.innerHTML) {
23980 this.doc.body.innerHTML = clean;
23985 cleanWordChars : function(input) {// change the chars to hex code
23986 var he = Roo.HtmlEditorCore;
23988 var output = input;
23989 Roo.each(he.swapCodes, function(sw) {
23990 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
23992 output = output.replace(swapper, sw[1]);
23999 cleanUpChildren : function (n)
24001 if (!n.childNodes.length) {
24004 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24005 this.cleanUpChild(n.childNodes[i]);
24012 cleanUpChild : function (node)
24015 //console.log(node);
24016 if (node.nodeName == "#text") {
24017 // clean up silly Windows -- stuff?
24020 if (node.nodeName == "#comment") {
24021 node.parentNode.removeChild(node);
24022 // clean up silly Windows -- stuff?
24025 var lcname = node.tagName.toLowerCase();
24026 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
24027 // whitelist of tags..
24029 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
24031 node.parentNode.removeChild(node);
24036 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
24038 // spans with no attributes - just remove them..
24039 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
24040 remove_keep_children = true;
24043 // remove <a name=....> as rendering on yahoo mailer is borked with this.
24044 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
24046 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
24047 // remove_keep_children = true;
24050 if (remove_keep_children) {
24051 this.cleanUpChildren(node);
24052 // inserts everything just before this node...
24053 while (node.childNodes.length) {
24054 var cn = node.childNodes[0];
24055 node.removeChild(cn);
24056 node.parentNode.insertBefore(cn, node);
24058 node.parentNode.removeChild(node);
24062 if (!node.attributes || !node.attributes.length) {
24067 this.cleanUpChildren(node);
24071 function cleanAttr(n,v)
24074 if (v.match(/^\./) || v.match(/^\//)) {
24077 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
24080 if (v.match(/^#/)) {
24083 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
24084 node.removeAttribute(n);
24088 var cwhite = this.cwhite;
24089 var cblack = this.cblack;
24091 function cleanStyle(n,v)
24093 if (v.match(/expression/)) { //XSS?? should we even bother..
24094 node.removeAttribute(n);
24098 var parts = v.split(/;/);
24101 Roo.each(parts, function(p) {
24102 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
24106 var l = p.split(':').shift().replace(/\s+/g,'');
24107 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
24109 if ( cwhite.length && cblack.indexOf(l) > -1) {
24110 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24111 //node.removeAttribute(n);
24115 // only allow 'c whitelisted system attributes'
24116 if ( cwhite.length && cwhite.indexOf(l) < 0) {
24117 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24118 //node.removeAttribute(n);
24128 if (clean.length) {
24129 node.setAttribute(n, clean.join(';'));
24131 node.removeAttribute(n);
24137 for (var i = node.attributes.length-1; i > -1 ; i--) {
24138 var a = node.attributes[i];
24141 if (a.name.toLowerCase().substr(0,2)=='on') {
24142 node.removeAttribute(a.name);
24145 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
24146 node.removeAttribute(a.name);
24149 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
24150 cleanAttr(a.name,a.value); // fixme..
24153 if (a.name == 'style') {
24154 cleanStyle(a.name,a.value);
24157 /// clean up MS crap..
24158 // tecnically this should be a list of valid class'es..
24161 if (a.name == 'class') {
24162 if (a.value.match(/^Mso/)) {
24163 node.removeAttribute('class');
24166 if (a.value.match(/^body$/)) {
24167 node.removeAttribute('class');
24178 this.cleanUpChildren(node);
24184 * Clean up MS wordisms...
24186 cleanWord : function(node)
24189 this.cleanWord(this.doc.body);
24194 node.nodeName == 'SPAN' &&
24195 !node.hasAttributes() &&
24196 node.childNodes.length == 1 &&
24197 node.firstChild.nodeName == "#text"
24199 var textNode = node.firstChild;
24200 node.removeChild(textNode);
24201 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24202 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
24204 node.parentNode.insertBefore(textNode, node);
24205 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24206 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
24208 node.parentNode.removeChild(node);
24211 if (node.nodeName == "#text") {
24212 // clean up silly Windows -- stuff?
24215 if (node.nodeName == "#comment") {
24216 node.parentNode.removeChild(node);
24217 // clean up silly Windows -- stuff?
24221 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
24222 node.parentNode.removeChild(node);
24225 //Roo.log(node.tagName);
24226 // remove - but keep children..
24227 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
24228 //Roo.log('-- removed');
24229 while (node.childNodes.length) {
24230 var cn = node.childNodes[0];
24231 node.removeChild(cn);
24232 node.parentNode.insertBefore(cn, node);
24233 // move node to parent - and clean it..
24234 this.cleanWord(cn);
24236 node.parentNode.removeChild(node);
24237 /// no need to iterate chidlren = it's got none..
24238 //this.iterateChildren(node, this.cleanWord);
24242 if (node.className.length) {
24244 var cn = node.className.split(/\W+/);
24246 Roo.each(cn, function(cls) {
24247 if (cls.match(/Mso[a-zA-Z]+/)) {
24252 node.className = cna.length ? cna.join(' ') : '';
24254 node.removeAttribute("class");
24258 if (node.hasAttribute("lang")) {
24259 node.removeAttribute("lang");
24262 if (node.hasAttribute("style")) {
24264 var styles = node.getAttribute("style").split(";");
24266 Roo.each(styles, function(s) {
24267 if (!s.match(/:/)) {
24270 var kv = s.split(":");
24271 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
24274 // what ever is left... we allow.
24277 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
24278 if (!nstyle.length) {
24279 node.removeAttribute('style');
24282 this.iterateChildren(node, this.cleanWord);
24288 * iterateChildren of a Node, calling fn each time, using this as the scole..
24289 * @param {DomNode} node node to iterate children of.
24290 * @param {Function} fn method of this class to call on each item.
24292 iterateChildren : function(node, fn)
24294 if (!node.childNodes.length) {
24297 for (var i = node.childNodes.length-1; i > -1 ; i--) {
24298 fn.call(this, node.childNodes[i])
24304 * cleanTableWidths.
24306 * Quite often pasting from word etc.. results in tables with column and widths.
24307 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
24310 cleanTableWidths : function(node)
24315 this.cleanTableWidths(this.doc.body);
24320 if (node.nodeName == "#text" || node.nodeName == "#comment") {
24323 Roo.log(node.tagName);
24324 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
24325 this.iterateChildren(node, this.cleanTableWidths);
24328 if (node.hasAttribute('width')) {
24329 node.removeAttribute('width');
24333 if (node.hasAttribute("style")) {
24336 var styles = node.getAttribute("style").split(";");
24338 Roo.each(styles, function(s) {
24339 if (!s.match(/:/)) {
24342 var kv = s.split(":");
24343 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
24346 // what ever is left... we allow.
24349 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
24350 if (!nstyle.length) {
24351 node.removeAttribute('style');
24355 this.iterateChildren(node, this.cleanTableWidths);
24363 domToHTML : function(currentElement, depth, nopadtext) {
24365 depth = depth || 0;
24366 nopadtext = nopadtext || false;
24368 if (!currentElement) {
24369 return this.domToHTML(this.doc.body);
24372 //Roo.log(currentElement);
24374 var allText = false;
24375 var nodeName = currentElement.nodeName;
24376 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
24378 if (nodeName == '#text') {
24380 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
24385 if (nodeName != 'BODY') {
24388 // Prints the node tagName, such as <A>, <IMG>, etc
24391 for(i = 0; i < currentElement.attributes.length;i++) {
24393 var aname = currentElement.attributes.item(i).name;
24394 if (!currentElement.attributes.item(i).value.length) {
24397 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
24400 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
24409 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
24412 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
24417 // Traverse the tree
24419 var currentElementChild = currentElement.childNodes.item(i);
24420 var allText = true;
24421 var innerHTML = '';
24423 while (currentElementChild) {
24424 // Formatting code (indent the tree so it looks nice on the screen)
24425 var nopad = nopadtext;
24426 if (lastnode == 'SPAN') {
24430 if (currentElementChild.nodeName == '#text') {
24431 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
24432 toadd = nopadtext ? toadd : toadd.trim();
24433 if (!nopad && toadd.length > 80) {
24434 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
24436 innerHTML += toadd;
24439 currentElementChild = currentElement.childNodes.item(i);
24445 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
24447 // Recursively traverse the tree structure of the child node
24448 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
24449 lastnode = currentElementChild.nodeName;
24451 currentElementChild=currentElement.childNodes.item(i);
24457 // The remaining code is mostly for formatting the tree
24458 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
24463 ret+= "</"+tagName+">";
24469 applyBlacklists : function()
24471 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
24472 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
24476 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
24477 if (b.indexOf(tag) > -1) {
24480 this.white.push(tag);
24484 Roo.each(w, function(tag) {
24485 if (b.indexOf(tag) > -1) {
24488 if (this.white.indexOf(tag) > -1) {
24491 this.white.push(tag);
24496 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
24497 if (w.indexOf(tag) > -1) {
24500 this.black.push(tag);
24504 Roo.each(b, function(tag) {
24505 if (w.indexOf(tag) > -1) {
24508 if (this.black.indexOf(tag) > -1) {
24511 this.black.push(tag);
24516 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
24517 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
24521 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
24522 if (b.indexOf(tag) > -1) {
24525 this.cwhite.push(tag);
24529 Roo.each(w, function(tag) {
24530 if (b.indexOf(tag) > -1) {
24533 if (this.cwhite.indexOf(tag) > -1) {
24536 this.cwhite.push(tag);
24541 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
24542 if (w.indexOf(tag) > -1) {
24545 this.cblack.push(tag);
24549 Roo.each(b, function(tag) {
24550 if (w.indexOf(tag) > -1) {
24553 if (this.cblack.indexOf(tag) > -1) {
24556 this.cblack.push(tag);
24561 setStylesheets : function(stylesheets)
24563 if(typeof(stylesheets) == 'string'){
24564 Roo.get(this.iframe.contentDocument.head).createChild({
24566 rel : 'stylesheet',
24575 Roo.each(stylesheets, function(s) {
24580 Roo.get(_this.iframe.contentDocument.head).createChild({
24582 rel : 'stylesheet',
24591 removeStylesheets : function()
24595 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
24600 setStyle : function(style)
24602 Roo.get(this.iframe.contentDocument.head).createChild({
24611 // hide stuff that is not compatible
24625 * @event specialkey
24629 * @cfg {String} fieldClass @hide
24632 * @cfg {String} focusClass @hide
24635 * @cfg {String} autoCreate @hide
24638 * @cfg {String} inputType @hide
24641 * @cfg {String} invalidClass @hide
24644 * @cfg {String} invalidText @hide
24647 * @cfg {String} msgFx @hide
24650 * @cfg {String} validateOnBlur @hide
24654 Roo.HtmlEditorCore.white = [
24655 'area', 'br', 'img', 'input', 'hr', 'wbr',
24657 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24658 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24659 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24660 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24661 'table', 'ul', 'xmp',
24663 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24666 'dir', 'menu', 'ol', 'ul', 'dl',
24672 Roo.HtmlEditorCore.black = [
24673 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24675 'base', 'basefont', 'bgsound', 'blink', 'body',
24676 'frame', 'frameset', 'head', 'html', 'ilayer',
24677 'iframe', 'layer', 'link', 'meta', 'object',
24678 'script', 'style' ,'title', 'xml' // clean later..
24680 Roo.HtmlEditorCore.clean = [
24681 'script', 'style', 'title', 'xml'
24683 Roo.HtmlEditorCore.remove = [
24688 Roo.HtmlEditorCore.ablack = [
24692 Roo.HtmlEditorCore.aclean = [
24693 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24697 Roo.HtmlEditorCore.pwhite= [
24698 'http', 'https', 'mailto'
24701 // white listed style attributes.
24702 Roo.HtmlEditorCore.cwhite= [
24703 // 'text-align', /// default is to allow most things..
24709 // black listed style attributes.
24710 Roo.HtmlEditorCore.cblack= [
24711 // 'font-size' -- this can be set by the project
24715 Roo.HtmlEditorCore.swapCodes =[
24734 * @class Roo.bootstrap.HtmlEditor
24735 * @extends Roo.bootstrap.TextArea
24736 * Bootstrap HtmlEditor class
24739 * Create a new HtmlEditor
24740 * @param {Object} config The config object
24743 Roo.bootstrap.HtmlEditor = function(config){
24744 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
24745 if (!this.toolbars) {
24746 this.toolbars = [];
24749 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
24752 * @event initialize
24753 * Fires when the editor is fully initialized (including the iframe)
24754 * @param {HtmlEditor} this
24759 * Fires when the editor is first receives the focus. Any insertion must wait
24760 * until after this event.
24761 * @param {HtmlEditor} this
24765 * @event beforesync
24766 * Fires before the textarea is updated with content from the editor iframe. Return false
24767 * to cancel the sync.
24768 * @param {HtmlEditor} this
24769 * @param {String} html
24773 * @event beforepush
24774 * Fires before the iframe editor is updated with content from the textarea. Return false
24775 * to cancel the push.
24776 * @param {HtmlEditor} this
24777 * @param {String} html
24782 * Fires when the textarea is updated with content from the editor iframe.
24783 * @param {HtmlEditor} this
24784 * @param {String} html
24789 * Fires when the iframe editor is updated with content from the textarea.
24790 * @param {HtmlEditor} this
24791 * @param {String} html
24795 * @event editmodechange
24796 * Fires when the editor switches edit modes
24797 * @param {HtmlEditor} this
24798 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
24800 editmodechange: true,
24802 * @event editorevent
24803 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
24804 * @param {HtmlEditor} this
24808 * @event firstfocus
24809 * Fires when on first focus - needed by toolbars..
24810 * @param {HtmlEditor} this
24815 * Auto save the htmlEditor value as a file into Events
24816 * @param {HtmlEditor} this
24820 * @event savedpreview
24821 * preview the saved version of htmlEditor
24822 * @param {HtmlEditor} this
24829 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
24833 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
24838 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
24843 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
24848 * @cfg {Number} height (in pixels)
24852 * @cfg {Number} width (in pixels)
24857 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
24860 stylesheets: false,
24865 // private properties
24866 validationEvent : false,
24868 initialized : false,
24871 onFocus : Roo.emptyFn,
24873 hideMode:'offsets',
24875 tbContainer : false,
24879 toolbarContainer :function() {
24880 return this.wrap.select('.x-html-editor-tb',true).first();
24884 * Protected method that will not generally be called directly. It
24885 * is called when the editor creates its toolbar. Override this method if you need to
24886 * add custom toolbar buttons.
24887 * @param {HtmlEditor} editor
24889 createToolbar : function(){
24890 Roo.log('renewing');
24891 Roo.log("create toolbars");
24893 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
24894 this.toolbars[0].render(this.toolbarContainer());
24898 // if (!editor.toolbars || !editor.toolbars.length) {
24899 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
24902 // for (var i =0 ; i < editor.toolbars.length;i++) {
24903 // editor.toolbars[i] = Roo.factory(
24904 // typeof(editor.toolbars[i]) == 'string' ?
24905 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
24906 // Roo.bootstrap.HtmlEditor);
24907 // editor.toolbars[i].init(editor);
24913 onRender : function(ct, position)
24915 // Roo.log("Call onRender: " + this.xtype);
24917 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
24919 this.wrap = this.inputEl().wrap({
24920 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24923 this.editorcore.onRender(ct, position);
24925 if (this.resizable) {
24926 this.resizeEl = new Roo.Resizable(this.wrap, {
24930 minHeight : this.height,
24931 height: this.height,
24932 handles : this.resizable,
24935 resize : function(r, w, h) {
24936 _t.onResize(w,h); // -something
24942 this.createToolbar(this);
24945 if(!this.width && this.resizable){
24946 this.setSize(this.wrap.getSize());
24948 if (this.resizeEl) {
24949 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
24950 // should trigger onReize..
24956 onResize : function(w, h)
24958 Roo.log('resize: ' +w + ',' + h );
24959 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
24963 if(this.inputEl() ){
24964 if(typeof w == 'number'){
24965 var aw = w - this.wrap.getFrameWidth('lr');
24966 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
24969 if(typeof h == 'number'){
24970 var tbh = -11; // fixme it needs to tool bar size!
24971 for (var i =0; i < this.toolbars.length;i++) {
24972 // fixme - ask toolbars for heights?
24973 tbh += this.toolbars[i].el.getHeight();
24974 //if (this.toolbars[i].footer) {
24975 // tbh += this.toolbars[i].footer.el.getHeight();
24983 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24984 ah -= 5; // knock a few pixes off for look..
24985 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
24989 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
24990 this.editorcore.onResize(ew,eh);
24995 * Toggles the editor between standard and source edit mode.
24996 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24998 toggleSourceEdit : function(sourceEditMode)
25000 this.editorcore.toggleSourceEdit(sourceEditMode);
25002 if(this.editorcore.sourceEditMode){
25003 Roo.log('editor - showing textarea');
25006 // Roo.log(this.syncValue());
25008 this.inputEl().removeClass(['hide', 'x-hidden']);
25009 this.inputEl().dom.removeAttribute('tabIndex');
25010 this.inputEl().focus();
25012 Roo.log('editor - hiding textarea');
25014 // Roo.log(this.pushValue());
25017 this.inputEl().addClass(['hide', 'x-hidden']);
25018 this.inputEl().dom.setAttribute('tabIndex', -1);
25019 //this.deferFocus();
25022 if(this.resizable){
25023 this.setSize(this.wrap.getSize());
25026 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
25029 // private (for BoxComponent)
25030 adjustSize : Roo.BoxComponent.prototype.adjustSize,
25032 // private (for BoxComponent)
25033 getResizeEl : function(){
25037 // private (for BoxComponent)
25038 getPositionEl : function(){
25043 initEvents : function(){
25044 this.originalValue = this.getValue();
25048 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25051 // markInvalid : Roo.emptyFn,
25053 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25056 // clearInvalid : Roo.emptyFn,
25058 setValue : function(v){
25059 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
25060 this.editorcore.pushValue();
25065 deferFocus : function(){
25066 this.focus.defer(10, this);
25070 focus : function(){
25071 this.editorcore.focus();
25077 onDestroy : function(){
25083 for (var i =0; i < this.toolbars.length;i++) {
25084 // fixme - ask toolbars for heights?
25085 this.toolbars[i].onDestroy();
25088 this.wrap.dom.innerHTML = '';
25089 this.wrap.remove();
25094 onFirstFocus : function(){
25095 //Roo.log("onFirstFocus");
25096 this.editorcore.onFirstFocus();
25097 for (var i =0; i < this.toolbars.length;i++) {
25098 this.toolbars[i].onFirstFocus();
25104 syncValue : function()
25106 this.editorcore.syncValue();
25109 pushValue : function()
25111 this.editorcore.pushValue();
25115 // hide stuff that is not compatible
25129 * @event specialkey
25133 * @cfg {String} fieldClass @hide
25136 * @cfg {String} focusClass @hide
25139 * @cfg {String} autoCreate @hide
25142 * @cfg {String} inputType @hide
25146 * @cfg {String} invalidText @hide
25149 * @cfg {String} msgFx @hide
25152 * @cfg {String} validateOnBlur @hide
25161 Roo.namespace('Roo.bootstrap.htmleditor');
25163 * @class Roo.bootstrap.HtmlEditorToolbar1
25169 new Roo.bootstrap.HtmlEditor({
25172 new Roo.bootstrap.HtmlEditorToolbar1({
25173 disable : { fonts: 1 , format: 1, ..., ... , ...],
25179 * @cfg {Object} disable List of elements to disable..
25180 * @cfg {Array} btns List of additional buttons.
25184 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
25187 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
25190 Roo.apply(this, config);
25192 // default disabled, based on 'good practice'..
25193 this.disable = this.disable || {};
25194 Roo.applyIf(this.disable, {
25197 specialElements : true
25199 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
25201 this.editor = config.editor;
25202 this.editorcore = config.editor.editorcore;
25204 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
25206 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25207 // dont call parent... till later.
25209 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
25214 editorcore : false,
25219 "h1","h2","h3","h4","h5","h6",
25221 "abbr", "acronym", "address", "cite", "samp", "var",
25225 onRender : function(ct, position)
25227 // Roo.log("Call onRender: " + this.xtype);
25229 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
25231 this.el.dom.style.marginBottom = '0';
25233 var editorcore = this.editorcore;
25234 var editor= this.editor;
25237 var btn = function(id,cmd , toggle, handler, html){
25239 var event = toggle ? 'toggle' : 'click';
25244 xns: Roo.bootstrap,
25248 enableToggle:toggle !== false,
25250 pressed : toggle ? false : null,
25253 a.listeners[toggle ? 'toggle' : 'click'] = function() {
25254 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
25260 // var cb_box = function...
25265 xns: Roo.bootstrap,
25270 xns: Roo.bootstrap,
25274 Roo.each(this.formats, function(f) {
25275 style.menu.items.push({
25277 xns: Roo.bootstrap,
25278 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
25283 editorcore.insertTag(this.tagname);
25290 children.push(style);
25292 btn('bold',false,true);
25293 btn('italic',false,true);
25294 btn('align-left', 'justifyleft',true);
25295 btn('align-center', 'justifycenter',true);
25296 btn('align-right' , 'justifyright',true);
25297 btn('link', false, false, function(btn) {
25298 //Roo.log("create link?");
25299 var url = prompt(this.createLinkText, this.defaultLinkValue);
25300 if(url && url != 'http:/'+'/'){
25301 this.editorcore.relayCmd('createlink', url);
25304 btn('list','insertunorderedlist',true);
25305 btn('pencil', false,true, function(btn){
25307 this.toggleSourceEdit(btn.pressed);
25310 if (this.editor.btns.length > 0) {
25311 for (var i = 0; i<this.editor.btns.length; i++) {
25312 children.push(this.editor.btns[i]);
25320 xns: Roo.bootstrap,
25325 xns: Roo.bootstrap,
25330 cog.menu.items.push({
25332 xns: Roo.bootstrap,
25333 html : Clean styles,
25338 editorcore.insertTag(this.tagname);
25347 this.xtype = 'NavSimplebar';
25349 for(var i=0;i< children.length;i++) {
25351 this.buttons.add(this.addxtypeChild(children[i]));
25355 editor.on('editorevent', this.updateToolbar, this);
25357 onBtnClick : function(id)
25359 this.editorcore.relayCmd(id);
25360 this.editorcore.focus();
25364 * Protected method that will not generally be called directly. It triggers
25365 * a toolbar update by reading the markup state of the current selection in the editor.
25367 updateToolbar: function(){
25369 if(!this.editorcore.activated){
25370 this.editor.onFirstFocus(); // is this neeed?
25374 var btns = this.buttons;
25375 var doc = this.editorcore.doc;
25376 btns.get('bold').setActive(doc.queryCommandState('bold'));
25377 btns.get('italic').setActive(doc.queryCommandState('italic'));
25378 //btns.get('underline').setActive(doc.queryCommandState('underline'));
25380 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
25381 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
25382 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
25384 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
25385 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
25388 var ans = this.editorcore.getAllAncestors();
25389 if (this.formatCombo) {
25392 var store = this.formatCombo.store;
25393 this.formatCombo.setValue("");
25394 for (var i =0; i < ans.length;i++) {
25395 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25397 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25405 // hides menus... - so this cant be on a menu...
25406 Roo.bootstrap.MenuMgr.hideAll();
25408 Roo.bootstrap.MenuMgr.hideAll();
25409 //this.editorsyncValue();
25411 onFirstFocus: function() {
25412 this.buttons.each(function(item){
25416 toggleSourceEdit : function(sourceEditMode){
25419 if(sourceEditMode){
25420 Roo.log("disabling buttons");
25421 this.buttons.each( function(item){
25422 if(item.cmd != 'pencil'){
25428 Roo.log("enabling buttons");
25429 if(this.editorcore.initialized){
25430 this.buttons.each( function(item){
25436 Roo.log("calling toggole on editor");
25437 // tell the editor that it's been pressed..
25438 this.editor.toggleSourceEdit(sourceEditMode);
25448 * @class Roo.bootstrap.Table.AbstractSelectionModel
25449 * @extends Roo.util.Observable
25450 * Abstract base class for grid SelectionModels. It provides the interface that should be
25451 * implemented by descendant classes. This class should not be directly instantiated.
25454 Roo.bootstrap.Table.AbstractSelectionModel = function(){
25455 this.locked = false;
25456 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
25460 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
25461 /** @ignore Called by the grid automatically. Do not call directly. */
25462 init : function(grid){
25468 * Locks the selections.
25471 this.locked = true;
25475 * Unlocks the selections.
25477 unlock : function(){
25478 this.locked = false;
25482 * Returns true if the selections are locked.
25483 * @return {Boolean}
25485 isLocked : function(){
25486 return this.locked;
25490 initEvents : function ()
25496 * @extends Roo.bootstrap.Table.AbstractSelectionModel
25497 * @class Roo.bootstrap.Table.RowSelectionModel
25498 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
25499 * It supports multiple selections and keyboard selection/navigation.
25501 * @param {Object} config
25504 Roo.bootstrap.Table.RowSelectionModel = function(config){
25505 Roo.apply(this, config);
25506 this.selections = new Roo.util.MixedCollection(false, function(o){
25511 this.lastActive = false;
25515 * @event selectionchange
25516 * Fires when the selection changes
25517 * @param {SelectionModel} this
25519 "selectionchange" : true,
25521 * @event afterselectionchange
25522 * Fires after the selection changes (eg. by key press or clicking)
25523 * @param {SelectionModel} this
25525 "afterselectionchange" : true,
25527 * @event beforerowselect
25528 * Fires when a row is selected being selected, return false to cancel.
25529 * @param {SelectionModel} this
25530 * @param {Number} rowIndex The selected index
25531 * @param {Boolean} keepExisting False if other selections will be cleared
25533 "beforerowselect" : true,
25536 * Fires when a row is selected.
25537 * @param {SelectionModel} this
25538 * @param {Number} rowIndex The selected index
25539 * @param {Roo.data.Record} r The record
25541 "rowselect" : true,
25543 * @event rowdeselect
25544 * Fires when a row is deselected.
25545 * @param {SelectionModel} this
25546 * @param {Number} rowIndex The selected index
25548 "rowdeselect" : true
25550 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
25551 this.locked = false;
25554 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
25556 * @cfg {Boolean} singleSelect
25557 * True to allow selection of only one row at a time (defaults to false)
25559 singleSelect : false,
25562 initEvents : function()
25565 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
25566 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
25567 //}else{ // allow click to work like normal
25568 // this.grid.on("rowclick", this.handleDragableRowClick, this);
25570 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
25571 this.grid.on("rowclick", this.handleMouseDown, this);
25573 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
25574 "up" : function(e){
25576 this.selectPrevious(e.shiftKey);
25577 }else if(this.last !== false && this.lastActive !== false){
25578 var last = this.last;
25579 this.selectRange(this.last, this.lastActive-1);
25580 this.grid.getView().focusRow(this.lastActive);
25581 if(last !== false){
25585 this.selectFirstRow();
25587 this.fireEvent("afterselectionchange", this);
25589 "down" : function(e){
25591 this.selectNext(e.shiftKey);
25592 }else if(this.last !== false && this.lastActive !== false){
25593 var last = this.last;
25594 this.selectRange(this.last, this.lastActive+1);
25595 this.grid.getView().focusRow(this.lastActive);
25596 if(last !== false){
25600 this.selectFirstRow();
25602 this.fireEvent("afterselectionchange", this);
25606 this.grid.store.on('load', function(){
25607 this.selections.clear();
25610 var view = this.grid.view;
25611 view.on("refresh", this.onRefresh, this);
25612 view.on("rowupdated", this.onRowUpdated, this);
25613 view.on("rowremoved", this.onRemove, this);
25618 onRefresh : function()
25620 var ds = this.grid.store, i, v = this.grid.view;
25621 var s = this.selections;
25622 s.each(function(r){
25623 if((i = ds.indexOfId(r.id)) != -1){
25632 onRemove : function(v, index, r){
25633 this.selections.remove(r);
25637 onRowUpdated : function(v, index, r){
25638 if(this.isSelected(r)){
25639 v.onRowSelect(index);
25645 * @param {Array} records The records to select
25646 * @param {Boolean} keepExisting (optional) True to keep existing selections
25648 selectRecords : function(records, keepExisting)
25651 this.clearSelections();
25653 var ds = this.grid.store;
25654 for(var i = 0, len = records.length; i < len; i++){
25655 this.selectRow(ds.indexOf(records[i]), true);
25660 * Gets the number of selected rows.
25663 getCount : function(){
25664 return this.selections.length;
25668 * Selects the first row in the grid.
25670 selectFirstRow : function(){
25675 * Select the last row.
25676 * @param {Boolean} keepExisting (optional) True to keep existing selections
25678 selectLastRow : function(keepExisting){
25679 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
25680 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
25684 * Selects the row immediately following the last selected row.
25685 * @param {Boolean} keepExisting (optional) True to keep existing selections
25687 selectNext : function(keepExisting)
25689 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
25690 this.selectRow(this.last+1, keepExisting);
25691 this.grid.getView().focusRow(this.last);
25696 * Selects the row that precedes the last selected row.
25697 * @param {Boolean} keepExisting (optional) True to keep existing selections
25699 selectPrevious : function(keepExisting){
25701 this.selectRow(this.last-1, keepExisting);
25702 this.grid.getView().focusRow(this.last);
25707 * Returns the selected records
25708 * @return {Array} Array of selected records
25710 getSelections : function(){
25711 return [].concat(this.selections.items);
25715 * Returns the first selected record.
25718 getSelected : function(){
25719 return this.selections.itemAt(0);
25724 * Clears all selections.
25726 clearSelections : function(fast)
25732 var ds = this.grid.store;
25733 var s = this.selections;
25734 s.each(function(r){
25735 this.deselectRow(ds.indexOfId(r.id));
25739 this.selections.clear();
25746 * Selects all rows.
25748 selectAll : function(){
25752 this.selections.clear();
25753 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
25754 this.selectRow(i, true);
25759 * Returns True if there is a selection.
25760 * @return {Boolean}
25762 hasSelection : function(){
25763 return this.selections.length > 0;
25767 * Returns True if the specified row is selected.
25768 * @param {Number/Record} record The record or index of the record to check
25769 * @return {Boolean}
25771 isSelected : function(index){
25772 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
25773 return (r && this.selections.key(r.id) ? true : false);
25777 * Returns True if the specified record id is selected.
25778 * @param {String} id The id of record to check
25779 * @return {Boolean}
25781 isIdSelected : function(id){
25782 return (this.selections.key(id) ? true : false);
25787 handleMouseDBClick : function(e, t){
25791 handleMouseDown : function(e, t)
25793 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
25794 if(this.isLocked() || rowIndex < 0 ){
25797 if(e.shiftKey && this.last !== false){
25798 var last = this.last;
25799 this.selectRange(last, rowIndex, e.ctrlKey);
25800 this.last = last; // reset the last
25804 var isSelected = this.isSelected(rowIndex);
25805 //Roo.log("select row:" + rowIndex);
25807 this.deselectRow(rowIndex);
25809 this.selectRow(rowIndex, true);
25813 if(e.button !== 0 && isSelected){
25814 alert('rowIndex 2: ' + rowIndex);
25815 view.focusRow(rowIndex);
25816 }else if(e.ctrlKey && isSelected){
25817 this.deselectRow(rowIndex);
25818 }else if(!isSelected){
25819 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
25820 view.focusRow(rowIndex);
25824 this.fireEvent("afterselectionchange", this);
25827 handleDragableRowClick : function(grid, rowIndex, e)
25829 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
25830 this.selectRow(rowIndex, false);
25831 grid.view.focusRow(rowIndex);
25832 this.fireEvent("afterselectionchange", this);
25837 * Selects multiple rows.
25838 * @param {Array} rows Array of the indexes of the row to select
25839 * @param {Boolean} keepExisting (optional) True to keep existing selections
25841 selectRows : function(rows, keepExisting){
25843 this.clearSelections();
25845 for(var i = 0, len = rows.length; i < len; i++){
25846 this.selectRow(rows[i], true);
25851 * Selects a range of rows. All rows in between startRow and endRow are also selected.
25852 * @param {Number} startRow The index of the first row in the range
25853 * @param {Number} endRow The index of the last row in the range
25854 * @param {Boolean} keepExisting (optional) True to retain existing selections
25856 selectRange : function(startRow, endRow, keepExisting){
25861 this.clearSelections();
25863 if(startRow <= endRow){
25864 for(var i = startRow; i <= endRow; i++){
25865 this.selectRow(i, true);
25868 for(var i = startRow; i >= endRow; i--){
25869 this.selectRow(i, true);
25875 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
25876 * @param {Number} startRow The index of the first row in the range
25877 * @param {Number} endRow The index of the last row in the range
25879 deselectRange : function(startRow, endRow, preventViewNotify){
25883 for(var i = startRow; i <= endRow; i++){
25884 this.deselectRow(i, preventViewNotify);
25890 * @param {Number} row The index of the row to select
25891 * @param {Boolean} keepExisting (optional) True to keep existing selections
25893 selectRow : function(index, keepExisting, preventViewNotify)
25895 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
25898 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
25899 if(!keepExisting || this.singleSelect){
25900 this.clearSelections();
25903 var r = this.grid.store.getAt(index);
25904 //console.log('selectRow - record id :' + r.id);
25906 this.selections.add(r);
25907 this.last = this.lastActive = index;
25908 if(!preventViewNotify){
25909 var proxy = new Roo.Element(
25910 this.grid.getRowDom(index)
25912 proxy.addClass('bg-info info');
25914 this.fireEvent("rowselect", this, index, r);
25915 this.fireEvent("selectionchange", this);
25921 * @param {Number} row The index of the row to deselect
25923 deselectRow : function(index, preventViewNotify)
25928 if(this.last == index){
25931 if(this.lastActive == index){
25932 this.lastActive = false;
25935 var r = this.grid.store.getAt(index);
25940 this.selections.remove(r);
25941 //.console.log('deselectRow - record id :' + r.id);
25942 if(!preventViewNotify){
25944 var proxy = new Roo.Element(
25945 this.grid.getRowDom(index)
25947 proxy.removeClass('bg-info info');
25949 this.fireEvent("rowdeselect", this, index);
25950 this.fireEvent("selectionchange", this);
25954 restoreLast : function(){
25956 this.last = this._last;
25961 acceptsNav : function(row, col, cm){
25962 return !cm.isHidden(col) && cm.isCellEditable(col, row);
25966 onEditorKey : function(field, e){
25967 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
25972 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
25974 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
25976 }else if(k == e.ENTER && !e.ctrlKey){
25980 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
25982 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
25984 }else if(k == e.ESC){
25988 g.startEditing(newCell[0], newCell[1]);
25994 * Ext JS Library 1.1.1
25995 * Copyright(c) 2006-2007, Ext JS, LLC.
25997 * Originally Released Under LGPL - original licence link has changed is not relivant.
26000 * <script type="text/javascript">
26004 * @class Roo.bootstrap.PagingToolbar
26005 * @extends Roo.bootstrap.NavSimplebar
26006 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26008 * Create a new PagingToolbar
26009 * @param {Object} config The config object
26010 * @param {Roo.data.Store} store
26012 Roo.bootstrap.PagingToolbar = function(config)
26014 // old args format still supported... - xtype is prefered..
26015 // created from xtype...
26017 this.ds = config.dataSource;
26019 if (config.store && !this.ds) {
26020 this.store= Roo.factory(config.store, Roo.data);
26021 this.ds = this.store;
26022 this.ds.xmodule = this.xmodule || false;
26025 this.toolbarItems = [];
26026 if (config.items) {
26027 this.toolbarItems = config.items;
26030 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
26035 this.bind(this.ds);
26038 if (Roo.bootstrap.version == 4) {
26039 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
26041 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
26046 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
26048 * @cfg {Roo.data.Store} dataSource
26049 * The underlying data store providing the paged data
26052 * @cfg {String/HTMLElement/Element} container
26053 * container The id or element that will contain the toolbar
26056 * @cfg {Boolean} displayInfo
26057 * True to display the displayMsg (defaults to false)
26060 * @cfg {Number} pageSize
26061 * The number of records to display per page (defaults to 20)
26065 * @cfg {String} displayMsg
26066 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26068 displayMsg : 'Displaying {0} - {1} of {2}',
26070 * @cfg {String} emptyMsg
26071 * The message to display when no records are found (defaults to "No data to display")
26073 emptyMsg : 'No data to display',
26075 * Customizable piece of the default paging text (defaults to "Page")
26078 beforePageText : "Page",
26080 * Customizable piece of the default paging text (defaults to "of %0")
26083 afterPageText : "of {0}",
26085 * Customizable piece of the default paging text (defaults to "First Page")
26088 firstText : "First Page",
26090 * Customizable piece of the default paging text (defaults to "Previous Page")
26093 prevText : "Previous Page",
26095 * Customizable piece of the default paging text (defaults to "Next Page")
26098 nextText : "Next Page",
26100 * Customizable piece of the default paging text (defaults to "Last Page")
26103 lastText : "Last Page",
26105 * Customizable piece of the default paging text (defaults to "Refresh")
26108 refreshText : "Refresh",
26112 onRender : function(ct, position)
26114 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
26115 this.navgroup.parentId = this.id;
26116 this.navgroup.onRender(this.el, null);
26117 // add the buttons to the navgroup
26119 if(this.displayInfo){
26120 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
26121 this.displayEl = this.el.select('.x-paging-info', true).first();
26122 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
26123 // this.displayEl = navel.el.select('span',true).first();
26129 Roo.each(_this.buttons, function(e){ // this might need to use render????
26130 Roo.factory(e).render(_this.el);
26134 Roo.each(_this.toolbarItems, function(e) {
26135 _this.navgroup.addItem(e);
26139 this.first = this.navgroup.addItem({
26140 tooltip: this.firstText,
26141 cls: "prev btn-outline-secondary",
26142 html : ' <i class="fa fa-step-backward"></i>',
26144 preventDefault: true,
26145 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
26148 this.prev = this.navgroup.addItem({
26149 tooltip: this.prevText,
26150 cls: "prev btn-outline-secondary",
26151 html : ' <i class="fa fa-backward"></i>',
26153 preventDefault: true,
26154 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
26156 //this.addSeparator();
26159 var field = this.navgroup.addItem( {
26161 cls : 'x-paging-position btn-outline-secondary',
26163 html : this.beforePageText +
26164 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
26165 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
26168 this.field = field.el.select('input', true).first();
26169 this.field.on("keydown", this.onPagingKeydown, this);
26170 this.field.on("focus", function(){this.dom.select();});
26173 this.afterTextEl = field.el.select('.x-paging-after',true).first();
26174 //this.field.setHeight(18);
26175 //this.addSeparator();
26176 this.next = this.navgroup.addItem({
26177 tooltip: this.nextText,
26178 cls: "next btn-outline-secondary",
26179 html : ' <i class="fa fa-forward"></i>',
26181 preventDefault: true,
26182 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
26184 this.last = this.navgroup.addItem({
26185 tooltip: this.lastText,
26186 html : ' <i class="fa fa-step-forward"></i>',
26187 cls: "next btn-outline-secondary",
26189 preventDefault: true,
26190 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
26192 //this.addSeparator();
26193 this.loading = this.navgroup.addItem({
26194 tooltip: this.refreshText,
26195 cls: "btn-outline-secondary",
26196 html : ' <i class="fa fa-refresh"></i>',
26197 preventDefault: true,
26198 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
26204 updateInfo : function(){
26205 if(this.displayEl){
26206 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
26207 var msg = count == 0 ?
26211 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
26213 this.displayEl.update(msg);
26218 onLoad : function(ds, r, o)
26220 this.cursor = o.params.start ? o.params.start : 0;
26222 var d = this.getPageData(),
26227 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
26228 this.field.dom.value = ap;
26229 this.first.setDisabled(ap == 1);
26230 this.prev.setDisabled(ap == 1);
26231 this.next.setDisabled(ap == ps);
26232 this.last.setDisabled(ap == ps);
26233 this.loading.enable();
26238 getPageData : function(){
26239 var total = this.ds.getTotalCount();
26242 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
26243 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
26248 onLoadError : function(){
26249 this.loading.enable();
26253 onPagingKeydown : function(e){
26254 var k = e.getKey();
26255 var d = this.getPageData();
26257 var v = this.field.dom.value, pageNum;
26258 if(!v || isNaN(pageNum = parseInt(v, 10))){
26259 this.field.dom.value = d.activePage;
26262 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
26263 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
26266 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))
26268 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
26269 this.field.dom.value = pageNum;
26270 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
26273 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
26275 var v = this.field.dom.value, pageNum;
26276 var increment = (e.shiftKey) ? 10 : 1;
26277 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
26280 if(!v || isNaN(pageNum = parseInt(v, 10))) {
26281 this.field.dom.value = d.activePage;
26284 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
26286 this.field.dom.value = parseInt(v, 10) + increment;
26287 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
26288 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
26295 beforeLoad : function(){
26297 this.loading.disable();
26302 onClick : function(which){
26311 ds.load({params:{start: 0, limit: this.pageSize}});
26314 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
26317 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
26320 var total = ds.getTotalCount();
26321 var extra = total % this.pageSize;
26322 var lastStart = extra ? (total - extra) : total-this.pageSize;
26323 ds.load({params:{start: lastStart, limit: this.pageSize}});
26326 ds.load({params:{start: this.cursor, limit: this.pageSize}});
26332 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
26333 * @param {Roo.data.Store} store The data store to unbind
26335 unbind : function(ds){
26336 ds.un("beforeload", this.beforeLoad, this);
26337 ds.un("load", this.onLoad, this);
26338 ds.un("loadexception", this.onLoadError, this);
26339 ds.un("remove", this.updateInfo, this);
26340 ds.un("add", this.updateInfo, this);
26341 this.ds = undefined;
26345 * Binds the paging toolbar to the specified {@link Roo.data.Store}
26346 * @param {Roo.data.Store} store The data store to bind
26348 bind : function(ds){
26349 ds.on("beforeload", this.beforeLoad, this);
26350 ds.on("load", this.onLoad, this);
26351 ds.on("loadexception", this.onLoadError, this);
26352 ds.on("remove", this.updateInfo, this);
26353 ds.on("add", this.updateInfo, this);
26364 * @class Roo.bootstrap.MessageBar
26365 * @extends Roo.bootstrap.Component
26366 * Bootstrap MessageBar class
26367 * @cfg {String} html contents of the MessageBar
26368 * @cfg {String} weight (info | success | warning | danger) default info
26369 * @cfg {String} beforeClass insert the bar before the given class
26370 * @cfg {Boolean} closable (true | false) default false
26371 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
26374 * Create a new Element
26375 * @param {Object} config The config object
26378 Roo.bootstrap.MessageBar = function(config){
26379 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
26382 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
26388 beforeClass: 'bootstrap-sticky-wrap',
26390 getAutoCreate : function(){
26394 cls: 'alert alert-dismissable alert-' + this.weight,
26399 html: this.html || ''
26405 cfg.cls += ' alert-messages-fixed';
26419 onRender : function(ct, position)
26421 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
26424 var cfg = Roo.apply({}, this.getAutoCreate());
26428 cfg.cls += ' ' + this.cls;
26431 cfg.style = this.style;
26433 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
26435 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26438 this.el.select('>button.close').on('click', this.hide, this);
26444 if (!this.rendered) {
26450 this.fireEvent('show', this);
26456 if (!this.rendered) {
26462 this.fireEvent('hide', this);
26465 update : function()
26467 // var e = this.el.dom.firstChild;
26469 // if(this.closable){
26470 // e = e.nextSibling;
26473 // e.data = this.html || '';
26475 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
26491 * @class Roo.bootstrap.Graph
26492 * @extends Roo.bootstrap.Component
26493 * Bootstrap Graph class
26497 @cfg {String} graphtype bar | vbar | pie
26498 @cfg {number} g_x coodinator | centre x (pie)
26499 @cfg {number} g_y coodinator | centre y (pie)
26500 @cfg {number} g_r radius (pie)
26501 @cfg {number} g_height height of the chart (respected by all elements in the set)
26502 @cfg {number} g_width width of the chart (respected by all elements in the set)
26503 @cfg {Object} title The title of the chart
26506 -opts (object) options for the chart
26508 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
26509 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
26511 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.
26512 o stacked (boolean) whether or not to tread values as in a stacked bar chart
26514 o stretch (boolean)
26516 -opts (object) options for the pie
26519 o startAngle (number)
26520 o endAngle (number)
26524 * Create a new Input
26525 * @param {Object} config The config object
26528 Roo.bootstrap.Graph = function(config){
26529 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
26535 * The img click event for the img.
26536 * @param {Roo.EventObject} e
26542 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
26553 //g_colors: this.colors,
26560 getAutoCreate : function(){
26571 onRender : function(ct,position){
26574 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
26576 if (typeof(Raphael) == 'undefined') {
26577 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
26581 this.raphael = Raphael(this.el.dom);
26583 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26584 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26585 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26586 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
26588 r.text(160, 10, "Single Series Chart").attr(txtattr);
26589 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
26590 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
26591 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
26593 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
26594 r.barchart(330, 10, 300, 220, data1);
26595 r.barchart(10, 250, 300, 220, data2, {stacked: true});
26596 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
26599 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
26600 // r.barchart(30, 30, 560, 250, xdata, {
26601 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
26602 // axis : "0 0 1 1",
26603 // axisxlabels : xdata
26604 // //yvalues : cols,
26607 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
26609 // this.load(null,xdata,{
26610 // axis : "0 0 1 1",
26611 // axisxlabels : xdata
26616 load : function(graphtype,xdata,opts)
26618 this.raphael.clear();
26620 graphtype = this.graphtype;
26625 var r = this.raphael,
26626 fin = function () {
26627 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
26629 fout = function () {
26630 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
26632 pfin = function() {
26633 this.sector.stop();
26634 this.sector.scale(1.1, 1.1, this.cx, this.cy);
26637 this.label[0].stop();
26638 this.label[0].attr({ r: 7.5 });
26639 this.label[1].attr({ "font-weight": 800 });
26642 pfout = function() {
26643 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
26646 this.label[0].animate({ r: 5 }, 500, "bounce");
26647 this.label[1].attr({ "font-weight": 400 });
26653 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
26656 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
26659 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
26660 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
26662 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
26669 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
26674 setTitle: function(o)
26679 initEvents: function() {
26682 this.el.on('click', this.onClick, this);
26686 onClick : function(e)
26688 Roo.log('img onclick');
26689 this.fireEvent('click', this, e);
26701 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26704 * @class Roo.bootstrap.dash.NumberBox
26705 * @extends Roo.bootstrap.Component
26706 * Bootstrap NumberBox class
26707 * @cfg {String} headline Box headline
26708 * @cfg {String} content Box content
26709 * @cfg {String} icon Box icon
26710 * @cfg {String} footer Footer text
26711 * @cfg {String} fhref Footer href
26714 * Create a new NumberBox
26715 * @param {Object} config The config object
26719 Roo.bootstrap.dash.NumberBox = function(config){
26720 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
26724 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
26733 getAutoCreate : function(){
26737 cls : 'small-box ',
26745 cls : 'roo-headline',
26746 html : this.headline
26750 cls : 'roo-content',
26751 html : this.content
26765 cls : 'ion ' + this.icon
26774 cls : 'small-box-footer',
26775 href : this.fhref || '#',
26779 cfg.cn.push(footer);
26786 onRender : function(ct,position){
26787 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
26794 setHeadline: function (value)
26796 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
26799 setFooter: function (value, href)
26801 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
26804 this.el.select('a.small-box-footer',true).first().attr('href', href);
26809 setContent: function (value)
26811 this.el.select('.roo-content',true).first().dom.innerHTML = value;
26814 initEvents: function()
26828 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26831 * @class Roo.bootstrap.dash.TabBox
26832 * @extends Roo.bootstrap.Component
26833 * Bootstrap TabBox class
26834 * @cfg {String} title Title of the TabBox
26835 * @cfg {String} icon Icon of the TabBox
26836 * @cfg {Boolean} showtabs (true|false) show the tabs default true
26837 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
26840 * Create a new TabBox
26841 * @param {Object} config The config object
26845 Roo.bootstrap.dash.TabBox = function(config){
26846 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
26851 * When a pane is added
26852 * @param {Roo.bootstrap.dash.TabPane} pane
26856 * @event activatepane
26857 * When a pane is activated
26858 * @param {Roo.bootstrap.dash.TabPane} pane
26860 "activatepane" : true
26868 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
26873 tabScrollable : false,
26875 getChildContainer : function()
26877 return this.el.select('.tab-content', true).first();
26880 getAutoCreate : function(){
26884 cls: 'pull-left header',
26892 cls: 'fa ' + this.icon
26898 cls: 'nav nav-tabs pull-right',
26904 if(this.tabScrollable){
26911 cls: 'nav nav-tabs pull-right',
26922 cls: 'nav-tabs-custom',
26927 cls: 'tab-content no-padding',
26935 initEvents : function()
26937 //Roo.log('add add pane handler');
26938 this.on('addpane', this.onAddPane, this);
26941 * Updates the box title
26942 * @param {String} html to set the title to.
26944 setTitle : function(value)
26946 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
26948 onAddPane : function(pane)
26950 this.panes.push(pane);
26951 //Roo.log('addpane');
26953 // tabs are rendere left to right..
26954 if(!this.showtabs){
26958 var ctr = this.el.select('.nav-tabs', true).first();
26961 var existing = ctr.select('.nav-tab',true);
26962 var qty = existing.getCount();;
26965 var tab = ctr.createChild({
26967 cls : 'nav-tab' + (qty ? '' : ' active'),
26975 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
26978 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
26980 pane.el.addClass('active');
26985 onTabClick : function(ev,un,ob,pane)
26987 //Roo.log('tab - prev default');
26988 ev.preventDefault();
26991 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
26992 pane.tab.addClass('active');
26993 //Roo.log(pane.title);
26994 this.getChildContainer().select('.tab-pane',true).removeClass('active');
26995 // technically we should have a deactivate event.. but maybe add later.
26996 // and it should not de-activate the selected tab...
26997 this.fireEvent('activatepane', pane);
26998 pane.el.addClass('active');
26999 pane.fireEvent('activate');
27004 getActivePane : function()
27007 Roo.each(this.panes, function(p) {
27008 if(p.el.hasClass('active')){
27029 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27031 * @class Roo.bootstrap.TabPane
27032 * @extends Roo.bootstrap.Component
27033 * Bootstrap TabPane class
27034 * @cfg {Boolean} active (false | true) Default false
27035 * @cfg {String} title title of panel
27039 * Create a new TabPane
27040 * @param {Object} config The config object
27043 Roo.bootstrap.dash.TabPane = function(config){
27044 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
27050 * When a pane is activated
27051 * @param {Roo.bootstrap.dash.TabPane} pane
27058 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
27063 // the tabBox that this is attached to.
27066 getAutoCreate : function()
27074 cfg.cls += ' active';
27079 initEvents : function()
27081 //Roo.log('trigger add pane handler');
27082 this.parent().fireEvent('addpane', this)
27086 * Updates the tab title
27087 * @param {String} html to set the title to.
27089 setTitle: function(str)
27095 this.tab.select('a', true).first().dom.innerHTML = str;
27112 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27115 * @class Roo.bootstrap.menu.Menu
27116 * @extends Roo.bootstrap.Component
27117 * Bootstrap Menu class - container for Menu
27118 * @cfg {String} html Text of the menu
27119 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
27120 * @cfg {String} icon Font awesome icon
27121 * @cfg {String} pos Menu align to (top | bottom) default bottom
27125 * Create a new Menu
27126 * @param {Object} config The config object
27130 Roo.bootstrap.menu.Menu = function(config){
27131 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
27135 * @event beforeshow
27136 * Fires before this menu is displayed
27137 * @param {Roo.bootstrap.menu.Menu} this
27141 * @event beforehide
27142 * Fires before this menu is hidden
27143 * @param {Roo.bootstrap.menu.Menu} this
27148 * Fires after this menu is displayed
27149 * @param {Roo.bootstrap.menu.Menu} this
27154 * Fires after this menu is hidden
27155 * @param {Roo.bootstrap.menu.Menu} this
27160 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
27161 * @param {Roo.bootstrap.menu.Menu} this
27162 * @param {Roo.EventObject} e
27169 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
27173 weight : 'default',
27178 getChildContainer : function() {
27179 if(this.isSubMenu){
27183 return this.el.select('ul.dropdown-menu', true).first();
27186 getAutoCreate : function()
27191 cls : 'roo-menu-text',
27199 cls : 'fa ' + this.icon
27210 cls : 'dropdown-button btn btn-' + this.weight,
27215 cls : 'dropdown-toggle btn btn-' + this.weight,
27225 cls : 'dropdown-menu'
27231 if(this.pos == 'top'){
27232 cfg.cls += ' dropup';
27235 if(this.isSubMenu){
27238 cls : 'dropdown-menu'
27245 onRender : function(ct, position)
27247 this.isSubMenu = ct.hasClass('dropdown-submenu');
27249 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
27252 initEvents : function()
27254 if(this.isSubMenu){
27258 this.hidden = true;
27260 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
27261 this.triggerEl.on('click', this.onTriggerPress, this);
27263 this.buttonEl = this.el.select('button.dropdown-button', true).first();
27264 this.buttonEl.on('click', this.onClick, this);
27270 if(this.isSubMenu){
27274 return this.el.select('ul.dropdown-menu', true).first();
27277 onClick : function(e)
27279 this.fireEvent("click", this, e);
27282 onTriggerPress : function(e)
27284 if (this.isVisible()) {
27291 isVisible : function(){
27292 return !this.hidden;
27297 this.fireEvent("beforeshow", this);
27299 this.hidden = false;
27300 this.el.addClass('open');
27302 Roo.get(document).on("mouseup", this.onMouseUp, this);
27304 this.fireEvent("show", this);
27311 this.fireEvent("beforehide", this);
27313 this.hidden = true;
27314 this.el.removeClass('open');
27316 Roo.get(document).un("mouseup", this.onMouseUp);
27318 this.fireEvent("hide", this);
27321 onMouseUp : function()
27335 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27338 * @class Roo.bootstrap.menu.Item
27339 * @extends Roo.bootstrap.Component
27340 * Bootstrap MenuItem class
27341 * @cfg {Boolean} submenu (true | false) default false
27342 * @cfg {String} html text of the item
27343 * @cfg {String} href the link
27344 * @cfg {Boolean} disable (true | false) default false
27345 * @cfg {Boolean} preventDefault (true | false) default true
27346 * @cfg {String} icon Font awesome icon
27347 * @cfg {String} pos Submenu align to (left | right) default right
27351 * Create a new Item
27352 * @param {Object} config The config object
27356 Roo.bootstrap.menu.Item = function(config){
27357 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
27361 * Fires when the mouse is hovering over this menu
27362 * @param {Roo.bootstrap.menu.Item} this
27363 * @param {Roo.EventObject} e
27368 * Fires when the mouse exits this menu
27369 * @param {Roo.bootstrap.menu.Item} this
27370 * @param {Roo.EventObject} e
27376 * The raw click event for the entire grid.
27377 * @param {Roo.EventObject} e
27383 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
27388 preventDefault: true,
27393 getAutoCreate : function()
27398 cls : 'roo-menu-item-text',
27406 cls : 'fa ' + this.icon
27415 href : this.href || '#',
27422 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
27426 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
27428 if(this.pos == 'left'){
27429 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
27436 initEvents : function()
27438 this.el.on('mouseover', this.onMouseOver, this);
27439 this.el.on('mouseout', this.onMouseOut, this);
27441 this.el.select('a', true).first().on('click', this.onClick, this);
27445 onClick : function(e)
27447 if(this.preventDefault){
27448 e.preventDefault();
27451 this.fireEvent("click", this, e);
27454 onMouseOver : function(e)
27456 if(this.submenu && this.pos == 'left'){
27457 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
27460 this.fireEvent("mouseover", this, e);
27463 onMouseOut : function(e)
27465 this.fireEvent("mouseout", this, e);
27477 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27480 * @class Roo.bootstrap.menu.Separator
27481 * @extends Roo.bootstrap.Component
27482 * Bootstrap Separator class
27485 * Create a new Separator
27486 * @param {Object} config The config object
27490 Roo.bootstrap.menu.Separator = function(config){
27491 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
27494 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
27496 getAutoCreate : function(){
27517 * @class Roo.bootstrap.Tooltip
27518 * Bootstrap Tooltip class
27519 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
27520 * to determine which dom element triggers the tooltip.
27522 * It needs to add support for additional attributes like tooltip-position
27525 * Create a new Toolti
27526 * @param {Object} config The config object
27529 Roo.bootstrap.Tooltip = function(config){
27530 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
27532 this.alignment = Roo.bootstrap.Tooltip.alignment;
27534 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
27535 this.alignment = config.alignment;
27540 Roo.apply(Roo.bootstrap.Tooltip, {
27542 * @function init initialize tooltip monitoring.
27546 currentTip : false,
27547 currentRegion : false,
27553 Roo.get(document).on('mouseover', this.enter ,this);
27554 Roo.get(document).on('mouseout', this.leave, this);
27557 this.currentTip = new Roo.bootstrap.Tooltip();
27560 enter : function(ev)
27562 var dom = ev.getTarget();
27564 //Roo.log(['enter',dom]);
27565 var el = Roo.fly(dom);
27566 if (this.currentEl) {
27568 //Roo.log(this.currentEl);
27569 //Roo.log(this.currentEl.contains(dom));
27570 if (this.currentEl == el) {
27573 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
27579 if (this.currentTip.el) {
27580 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
27584 if(!el || el.dom == document){
27590 // you can not look for children, as if el is the body.. then everythign is the child..
27591 if (!el.attr('tooltip')) { //
27592 if (!el.select("[tooltip]").elements.length) {
27595 // is the mouse over this child...?
27596 bindEl = el.select("[tooltip]").first();
27597 var xy = ev.getXY();
27598 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
27599 //Roo.log("not in region.");
27602 //Roo.log("child element over..");
27605 this.currentEl = bindEl;
27606 this.currentTip.bind(bindEl);
27607 this.currentRegion = Roo.lib.Region.getRegion(dom);
27608 this.currentTip.enter();
27611 leave : function(ev)
27613 var dom = ev.getTarget();
27614 //Roo.log(['leave',dom]);
27615 if (!this.currentEl) {
27620 if (dom != this.currentEl.dom) {
27623 var xy = ev.getXY();
27624 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
27627 // only activate leave if mouse cursor is outside... bounding box..
27632 if (this.currentTip) {
27633 this.currentTip.leave();
27635 //Roo.log('clear currentEl');
27636 this.currentEl = false;
27641 'left' : ['r-l', [-2,0], 'right'],
27642 'right' : ['l-r', [2,0], 'left'],
27643 'bottom' : ['t-b', [0,2], 'top'],
27644 'top' : [ 'b-t', [0,-2], 'bottom']
27650 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
27655 delay : null, // can be { show : 300 , hide: 500}
27659 hoverState : null, //???
27661 placement : 'bottom',
27665 getAutoCreate : function(){
27672 cls : 'tooltip-arrow'
27675 cls : 'tooltip-inner'
27682 bind : function(el)
27688 enter : function () {
27690 if (this.timeout != null) {
27691 clearTimeout(this.timeout);
27694 this.hoverState = 'in';
27695 //Roo.log("enter - show");
27696 if (!this.delay || !this.delay.show) {
27701 this.timeout = setTimeout(function () {
27702 if (_t.hoverState == 'in') {
27705 }, this.delay.show);
27709 clearTimeout(this.timeout);
27711 this.hoverState = 'out';
27712 if (!this.delay || !this.delay.hide) {
27718 this.timeout = setTimeout(function () {
27719 //Roo.log("leave - timeout");
27721 if (_t.hoverState == 'out') {
27723 Roo.bootstrap.Tooltip.currentEl = false;
27728 show : function (msg)
27731 this.render(document.body);
27734 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
27736 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
27738 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
27740 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
27742 var placement = typeof this.placement == 'function' ?
27743 this.placement.call(this, this.el, on_el) :
27746 var autoToken = /\s?auto?\s?/i;
27747 var autoPlace = autoToken.test(placement);
27749 placement = placement.replace(autoToken, '') || 'top';
27753 //this.el.setXY([0,0]);
27755 //this.el.dom.style.display='block';
27757 //this.el.appendTo(on_el);
27759 var p = this.getPosition();
27760 var box = this.el.getBox();
27766 var align = this.alignment[placement];
27768 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
27770 if(placement == 'top' || placement == 'bottom'){
27772 placement = 'right';
27775 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
27776 placement = 'left';
27779 var scroll = Roo.select('body', true).first().getScroll();
27781 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
27785 align = this.alignment[placement];
27788 this.el.alignTo(this.bindEl, align[0],align[1]);
27789 //var arrow = this.el.select('.arrow',true).first();
27790 //arrow.set(align[2],
27792 this.el.addClass(placement);
27794 this.el.addClass('in fade');
27796 this.hoverState = null;
27798 if (this.el.hasClass('fade')) {
27809 //this.el.setXY([0,0]);
27810 this.el.removeClass('in');
27826 * @class Roo.bootstrap.LocationPicker
27827 * @extends Roo.bootstrap.Component
27828 * Bootstrap LocationPicker class
27829 * @cfg {Number} latitude Position when init default 0
27830 * @cfg {Number} longitude Position when init default 0
27831 * @cfg {Number} zoom default 15
27832 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
27833 * @cfg {Boolean} mapTypeControl default false
27834 * @cfg {Boolean} disableDoubleClickZoom default false
27835 * @cfg {Boolean} scrollwheel default true
27836 * @cfg {Boolean} streetViewControl default false
27837 * @cfg {Number} radius default 0
27838 * @cfg {String} locationName
27839 * @cfg {Boolean} draggable default true
27840 * @cfg {Boolean} enableAutocomplete default false
27841 * @cfg {Boolean} enableReverseGeocode default true
27842 * @cfg {String} markerTitle
27845 * Create a new LocationPicker
27846 * @param {Object} config The config object
27850 Roo.bootstrap.LocationPicker = function(config){
27852 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
27857 * Fires when the picker initialized.
27858 * @param {Roo.bootstrap.LocationPicker} this
27859 * @param {Google Location} location
27863 * @event positionchanged
27864 * Fires when the picker position changed.
27865 * @param {Roo.bootstrap.LocationPicker} this
27866 * @param {Google Location} location
27868 positionchanged : true,
27871 * Fires when the map resize.
27872 * @param {Roo.bootstrap.LocationPicker} this
27877 * Fires when the map show.
27878 * @param {Roo.bootstrap.LocationPicker} this
27883 * Fires when the map hide.
27884 * @param {Roo.bootstrap.LocationPicker} this
27889 * Fires when click the map.
27890 * @param {Roo.bootstrap.LocationPicker} this
27891 * @param {Map event} e
27895 * @event mapRightClick
27896 * Fires when right click the map.
27897 * @param {Roo.bootstrap.LocationPicker} this
27898 * @param {Map event} e
27900 mapRightClick : true,
27902 * @event markerClick
27903 * Fires when click the marker.
27904 * @param {Roo.bootstrap.LocationPicker} this
27905 * @param {Map event} e
27907 markerClick : true,
27909 * @event markerRightClick
27910 * Fires when right click the marker.
27911 * @param {Roo.bootstrap.LocationPicker} this
27912 * @param {Map event} e
27914 markerRightClick : true,
27916 * @event OverlayViewDraw
27917 * Fires when OverlayView Draw
27918 * @param {Roo.bootstrap.LocationPicker} this
27920 OverlayViewDraw : true,
27922 * @event OverlayViewOnAdd
27923 * Fires when OverlayView Draw
27924 * @param {Roo.bootstrap.LocationPicker} this
27926 OverlayViewOnAdd : true,
27928 * @event OverlayViewOnRemove
27929 * Fires when OverlayView Draw
27930 * @param {Roo.bootstrap.LocationPicker} this
27932 OverlayViewOnRemove : true,
27934 * @event OverlayViewShow
27935 * Fires when OverlayView Draw
27936 * @param {Roo.bootstrap.LocationPicker} this
27937 * @param {Pixel} cpx
27939 OverlayViewShow : true,
27941 * @event OverlayViewHide
27942 * Fires when OverlayView Draw
27943 * @param {Roo.bootstrap.LocationPicker} this
27945 OverlayViewHide : true,
27947 * @event loadexception
27948 * Fires when load google lib failed.
27949 * @param {Roo.bootstrap.LocationPicker} this
27951 loadexception : true
27956 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
27958 gMapContext: false,
27964 mapTypeControl: false,
27965 disableDoubleClickZoom: false,
27967 streetViewControl: false,
27971 enableAutocomplete: false,
27972 enableReverseGeocode: true,
27975 getAutoCreate: function()
27980 cls: 'roo-location-picker'
27986 initEvents: function(ct, position)
27988 if(!this.el.getWidth() || this.isApplied()){
27992 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27997 initial: function()
27999 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
28000 this.fireEvent('loadexception', this);
28004 if(!this.mapTypeId){
28005 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
28008 this.gMapContext = this.GMapContext();
28010 this.initOverlayView();
28012 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
28016 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
28017 _this.setPosition(_this.gMapContext.marker.position);
28020 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
28021 _this.fireEvent('mapClick', this, event);
28025 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
28026 _this.fireEvent('mapRightClick', this, event);
28030 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
28031 _this.fireEvent('markerClick', this, event);
28035 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
28036 _this.fireEvent('markerRightClick', this, event);
28040 this.setPosition(this.gMapContext.location);
28042 this.fireEvent('initial', this, this.gMapContext.location);
28045 initOverlayView: function()
28049 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
28053 _this.fireEvent('OverlayViewDraw', _this);
28058 _this.fireEvent('OverlayViewOnAdd', _this);
28061 onRemove: function()
28063 _this.fireEvent('OverlayViewOnRemove', _this);
28066 show: function(cpx)
28068 _this.fireEvent('OverlayViewShow', _this, cpx);
28073 _this.fireEvent('OverlayViewHide', _this);
28079 fromLatLngToContainerPixel: function(event)
28081 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
28084 isApplied: function()
28086 return this.getGmapContext() == false ? false : true;
28089 getGmapContext: function()
28091 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
28094 GMapContext: function()
28096 var position = new google.maps.LatLng(this.latitude, this.longitude);
28098 var _map = new google.maps.Map(this.el.dom, {
28101 mapTypeId: this.mapTypeId,
28102 mapTypeControl: this.mapTypeControl,
28103 disableDoubleClickZoom: this.disableDoubleClickZoom,
28104 scrollwheel: this.scrollwheel,
28105 streetViewControl: this.streetViewControl,
28106 locationName: this.locationName,
28107 draggable: this.draggable,
28108 enableAutocomplete: this.enableAutocomplete,
28109 enableReverseGeocode: this.enableReverseGeocode
28112 var _marker = new google.maps.Marker({
28113 position: position,
28115 title: this.markerTitle,
28116 draggable: this.draggable
28123 location: position,
28124 radius: this.radius,
28125 locationName: this.locationName,
28126 addressComponents: {
28127 formatted_address: null,
28128 addressLine1: null,
28129 addressLine2: null,
28131 streetNumber: null,
28135 stateOrProvince: null
28138 domContainer: this.el.dom,
28139 geodecoder: new google.maps.Geocoder()
28143 drawCircle: function(center, radius, options)
28145 if (this.gMapContext.circle != null) {
28146 this.gMapContext.circle.setMap(null);
28150 options = Roo.apply({}, options, {
28151 strokeColor: "#0000FF",
28152 strokeOpacity: .35,
28154 fillColor: "#0000FF",
28158 options.map = this.gMapContext.map;
28159 options.radius = radius;
28160 options.center = center;
28161 this.gMapContext.circle = new google.maps.Circle(options);
28162 return this.gMapContext.circle;
28168 setPosition: function(location)
28170 this.gMapContext.location = location;
28171 this.gMapContext.marker.setPosition(location);
28172 this.gMapContext.map.panTo(location);
28173 this.drawCircle(location, this.gMapContext.radius, {});
28177 if (this.gMapContext.settings.enableReverseGeocode) {
28178 this.gMapContext.geodecoder.geocode({
28179 latLng: this.gMapContext.location
28180 }, function(results, status) {
28182 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
28183 _this.gMapContext.locationName = results[0].formatted_address;
28184 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
28186 _this.fireEvent('positionchanged', this, location);
28193 this.fireEvent('positionchanged', this, location);
28198 google.maps.event.trigger(this.gMapContext.map, "resize");
28200 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
28202 this.fireEvent('resize', this);
28205 setPositionByLatLng: function(latitude, longitude)
28207 this.setPosition(new google.maps.LatLng(latitude, longitude));
28210 getCurrentPosition: function()
28213 latitude: this.gMapContext.location.lat(),
28214 longitude: this.gMapContext.location.lng()
28218 getAddressName: function()
28220 return this.gMapContext.locationName;
28223 getAddressComponents: function()
28225 return this.gMapContext.addressComponents;
28228 address_component_from_google_geocode: function(address_components)
28232 for (var i = 0; i < address_components.length; i++) {
28233 var component = address_components[i];
28234 if (component.types.indexOf("postal_code") >= 0) {
28235 result.postalCode = component.short_name;
28236 } else if (component.types.indexOf("street_number") >= 0) {
28237 result.streetNumber = component.short_name;
28238 } else if (component.types.indexOf("route") >= 0) {
28239 result.streetName = component.short_name;
28240 } else if (component.types.indexOf("neighborhood") >= 0) {
28241 result.city = component.short_name;
28242 } else if (component.types.indexOf("locality") >= 0) {
28243 result.city = component.short_name;
28244 } else if (component.types.indexOf("sublocality") >= 0) {
28245 result.district = component.short_name;
28246 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
28247 result.stateOrProvince = component.short_name;
28248 } else if (component.types.indexOf("country") >= 0) {
28249 result.country = component.short_name;
28253 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
28254 result.addressLine2 = "";
28258 setZoomLevel: function(zoom)
28260 this.gMapContext.map.setZoom(zoom);
28273 this.fireEvent('show', this);
28284 this.fireEvent('hide', this);
28289 Roo.apply(Roo.bootstrap.LocationPicker, {
28291 OverlayView : function(map, options)
28293 options = options || {};
28300 * @class Roo.bootstrap.Alert
28301 * @extends Roo.bootstrap.Component
28302 * Bootstrap Alert class - shows an alert area box
28304 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
28305 Enter a valid email address
28308 * @cfg {String} title The title of alert
28309 * @cfg {String} html The content of alert
28310 * @cfg {String} weight ( success | info | warning | danger )
28311 * @cfg {String} faicon font-awesomeicon
28314 * Create a new alert
28315 * @param {Object} config The config object
28319 Roo.bootstrap.Alert = function(config){
28320 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
28324 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
28331 getAutoCreate : function()
28340 cls : 'roo-alert-icon'
28345 cls : 'roo-alert-title',
28350 cls : 'roo-alert-text',
28357 cfg.cn[0].cls += ' fa ' + this.faicon;
28361 cfg.cls += ' alert-' + this.weight;
28367 initEvents: function()
28369 this.el.setVisibilityMode(Roo.Element.DISPLAY);
28372 setTitle : function(str)
28374 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
28377 setText : function(str)
28379 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
28382 setWeight : function(weight)
28385 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
28388 this.weight = weight;
28390 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
28393 setIcon : function(icon)
28396 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
28399 this.faicon = icon;
28401 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
28422 * @class Roo.bootstrap.UploadCropbox
28423 * @extends Roo.bootstrap.Component
28424 * Bootstrap UploadCropbox class
28425 * @cfg {String} emptyText show when image has been loaded
28426 * @cfg {String} rotateNotify show when image too small to rotate
28427 * @cfg {Number} errorTimeout default 3000
28428 * @cfg {Number} minWidth default 300
28429 * @cfg {Number} minHeight default 300
28430 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
28431 * @cfg {Boolean} isDocument (true|false) default false
28432 * @cfg {String} url action url
28433 * @cfg {String} paramName default 'imageUpload'
28434 * @cfg {String} method default POST
28435 * @cfg {Boolean} loadMask (true|false) default true
28436 * @cfg {Boolean} loadingText default 'Loading...'
28439 * Create a new UploadCropbox
28440 * @param {Object} config The config object
28443 Roo.bootstrap.UploadCropbox = function(config){
28444 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
28448 * @event beforeselectfile
28449 * Fire before select file
28450 * @param {Roo.bootstrap.UploadCropbox} this
28452 "beforeselectfile" : true,
28455 * Fire after initEvent
28456 * @param {Roo.bootstrap.UploadCropbox} this
28461 * Fire after initEvent
28462 * @param {Roo.bootstrap.UploadCropbox} this
28463 * @param {String} data
28468 * Fire when preparing the file data
28469 * @param {Roo.bootstrap.UploadCropbox} this
28470 * @param {Object} file
28475 * Fire when get exception
28476 * @param {Roo.bootstrap.UploadCropbox} this
28477 * @param {XMLHttpRequest} xhr
28479 "exception" : true,
28481 * @event beforeloadcanvas
28482 * Fire before load the canvas
28483 * @param {Roo.bootstrap.UploadCropbox} this
28484 * @param {String} src
28486 "beforeloadcanvas" : true,
28489 * Fire when trash image
28490 * @param {Roo.bootstrap.UploadCropbox} this
28495 * Fire when download the image
28496 * @param {Roo.bootstrap.UploadCropbox} this
28500 * @event footerbuttonclick
28501 * Fire when footerbuttonclick
28502 * @param {Roo.bootstrap.UploadCropbox} this
28503 * @param {String} type
28505 "footerbuttonclick" : true,
28509 * @param {Roo.bootstrap.UploadCropbox} this
28514 * Fire when rotate the image
28515 * @param {Roo.bootstrap.UploadCropbox} this
28516 * @param {String} pos
28521 * Fire when inspect the file
28522 * @param {Roo.bootstrap.UploadCropbox} this
28523 * @param {Object} file
28528 * Fire when xhr upload the file
28529 * @param {Roo.bootstrap.UploadCropbox} this
28530 * @param {Object} data
28535 * Fire when arrange the file data
28536 * @param {Roo.bootstrap.UploadCropbox} this
28537 * @param {Object} formData
28542 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
28545 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
28547 emptyText : 'Click to upload image',
28548 rotateNotify : 'Image is too small to rotate',
28549 errorTimeout : 3000,
28563 cropType : 'image/jpeg',
28565 canvasLoaded : false,
28566 isDocument : false,
28568 paramName : 'imageUpload',
28570 loadingText : 'Loading...',
28573 getAutoCreate : function()
28577 cls : 'roo-upload-cropbox',
28581 cls : 'roo-upload-cropbox-selector',
28586 cls : 'roo-upload-cropbox-body',
28587 style : 'cursor:pointer',
28591 cls : 'roo-upload-cropbox-preview'
28595 cls : 'roo-upload-cropbox-thumb'
28599 cls : 'roo-upload-cropbox-empty-notify',
28600 html : this.emptyText
28604 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
28605 html : this.rotateNotify
28611 cls : 'roo-upload-cropbox-footer',
28614 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
28624 onRender : function(ct, position)
28626 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
28628 if (this.buttons.length) {
28630 Roo.each(this.buttons, function(bb) {
28632 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
28634 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
28640 this.maskEl = this.el;
28644 initEvents : function()
28646 this.urlAPI = (window.createObjectURL && window) ||
28647 (window.URL && URL.revokeObjectURL && URL) ||
28648 (window.webkitURL && webkitURL);
28650 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
28651 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28653 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
28654 this.selectorEl.hide();
28656 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
28657 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28659 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
28660 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28661 this.thumbEl.hide();
28663 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
28664 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28666 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
28667 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28668 this.errorEl.hide();
28670 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
28671 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28672 this.footerEl.hide();
28674 this.setThumbBoxSize();
28680 this.fireEvent('initial', this);
28687 window.addEventListener("resize", function() { _this.resize(); } );
28689 this.bodyEl.on('click', this.beforeSelectFile, this);
28692 this.bodyEl.on('touchstart', this.onTouchStart, this);
28693 this.bodyEl.on('touchmove', this.onTouchMove, this);
28694 this.bodyEl.on('touchend', this.onTouchEnd, this);
28698 this.bodyEl.on('mousedown', this.onMouseDown, this);
28699 this.bodyEl.on('mousemove', this.onMouseMove, this);
28700 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
28701 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
28702 Roo.get(document).on('mouseup', this.onMouseUp, this);
28705 this.selectorEl.on('change', this.onFileSelected, this);
28711 this.baseScale = 1;
28713 this.baseRotate = 1;
28714 this.dragable = false;
28715 this.pinching = false;
28718 this.cropData = false;
28719 this.notifyEl.dom.innerHTML = this.emptyText;
28721 this.selectorEl.dom.value = '';
28725 resize : function()
28727 if(this.fireEvent('resize', this) != false){
28728 this.setThumbBoxPosition();
28729 this.setCanvasPosition();
28733 onFooterButtonClick : function(e, el, o, type)
28736 case 'rotate-left' :
28737 this.onRotateLeft(e);
28739 case 'rotate-right' :
28740 this.onRotateRight(e);
28743 this.beforeSelectFile(e);
28758 this.fireEvent('footerbuttonclick', this, type);
28761 beforeSelectFile : function(e)
28763 e.preventDefault();
28765 if(this.fireEvent('beforeselectfile', this) != false){
28766 this.selectorEl.dom.click();
28770 onFileSelected : function(e)
28772 e.preventDefault();
28774 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28778 var file = this.selectorEl.dom.files[0];
28780 if(this.fireEvent('inspect', this, file) != false){
28781 this.prepare(file);
28786 trash : function(e)
28788 this.fireEvent('trash', this);
28791 download : function(e)
28793 this.fireEvent('download', this);
28796 loadCanvas : function(src)
28798 if(this.fireEvent('beforeloadcanvas', this, src) != false){
28802 this.imageEl = document.createElement('img');
28806 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
28808 this.imageEl.src = src;
28812 onLoadCanvas : function()
28814 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
28815 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
28817 this.bodyEl.un('click', this.beforeSelectFile, this);
28819 this.notifyEl.hide();
28820 this.thumbEl.show();
28821 this.footerEl.show();
28823 this.baseRotateLevel();
28825 if(this.isDocument){
28826 this.setThumbBoxSize();
28829 this.setThumbBoxPosition();
28831 this.baseScaleLevel();
28837 this.canvasLoaded = true;
28840 this.maskEl.unmask();
28845 setCanvasPosition : function()
28847 if(!this.canvasEl){
28851 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
28852 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
28854 this.previewEl.setLeft(pw);
28855 this.previewEl.setTop(ph);
28859 onMouseDown : function(e)
28863 this.dragable = true;
28864 this.pinching = false;
28866 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
28867 this.dragable = false;
28871 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28872 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28876 onMouseMove : function(e)
28880 if(!this.canvasLoaded){
28884 if (!this.dragable){
28888 var minX = Math.ceil(this.thumbEl.getLeft(true));
28889 var minY = Math.ceil(this.thumbEl.getTop(true));
28891 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
28892 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
28894 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28895 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28897 x = x - this.mouseX;
28898 y = y - this.mouseY;
28900 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
28901 var bgY = Math.ceil(y + this.previewEl.getTop(true));
28903 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
28904 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
28906 this.previewEl.setLeft(bgX);
28907 this.previewEl.setTop(bgY);
28909 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28910 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28913 onMouseUp : function(e)
28917 this.dragable = false;
28920 onMouseWheel : function(e)
28924 this.startScale = this.scale;
28926 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
28928 if(!this.zoomable()){
28929 this.scale = this.startScale;
28938 zoomable : function()
28940 var minScale = this.thumbEl.getWidth() / this.minWidth;
28942 if(this.minWidth < this.minHeight){
28943 minScale = this.thumbEl.getHeight() / this.minHeight;
28946 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
28947 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
28951 (this.rotate == 0 || this.rotate == 180) &&
28953 width > this.imageEl.OriginWidth ||
28954 height > this.imageEl.OriginHeight ||
28955 (width < this.minWidth && height < this.minHeight)
28963 (this.rotate == 90 || this.rotate == 270) &&
28965 width > this.imageEl.OriginWidth ||
28966 height > this.imageEl.OriginHeight ||
28967 (width < this.minHeight && height < this.minWidth)
28974 !this.isDocument &&
28975 (this.rotate == 0 || this.rotate == 180) &&
28977 width < this.minWidth ||
28978 width > this.imageEl.OriginWidth ||
28979 height < this.minHeight ||
28980 height > this.imageEl.OriginHeight
28987 !this.isDocument &&
28988 (this.rotate == 90 || this.rotate == 270) &&
28990 width < this.minHeight ||
28991 width > this.imageEl.OriginWidth ||
28992 height < this.minWidth ||
28993 height > this.imageEl.OriginHeight
29003 onRotateLeft : function(e)
29005 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29007 var minScale = this.thumbEl.getWidth() / this.minWidth;
29009 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29010 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29012 this.startScale = this.scale;
29014 while (this.getScaleLevel() < minScale){
29016 this.scale = this.scale + 1;
29018 if(!this.zoomable()){
29023 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29024 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29029 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29036 this.scale = this.startScale;
29038 this.onRotateFail();
29043 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29045 if(this.isDocument){
29046 this.setThumbBoxSize();
29047 this.setThumbBoxPosition();
29048 this.setCanvasPosition();
29053 this.fireEvent('rotate', this, 'left');
29057 onRotateRight : function(e)
29059 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29061 var minScale = this.thumbEl.getWidth() / this.minWidth;
29063 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29064 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29066 this.startScale = this.scale;
29068 while (this.getScaleLevel() < minScale){
29070 this.scale = this.scale + 1;
29072 if(!this.zoomable()){
29077 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29078 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29083 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29090 this.scale = this.startScale;
29092 this.onRotateFail();
29097 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29099 if(this.isDocument){
29100 this.setThumbBoxSize();
29101 this.setThumbBoxPosition();
29102 this.setCanvasPosition();
29107 this.fireEvent('rotate', this, 'right');
29110 onRotateFail : function()
29112 this.errorEl.show(true);
29116 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
29121 this.previewEl.dom.innerHTML = '';
29123 var canvasEl = document.createElement("canvas");
29125 var contextEl = canvasEl.getContext("2d");
29127 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29128 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29129 var center = this.imageEl.OriginWidth / 2;
29131 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
29132 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29133 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29134 center = this.imageEl.OriginHeight / 2;
29137 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
29139 contextEl.translate(center, center);
29140 contextEl.rotate(this.rotate * Math.PI / 180);
29142 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29144 this.canvasEl = document.createElement("canvas");
29146 this.contextEl = this.canvasEl.getContext("2d");
29148 switch (this.rotate) {
29151 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29152 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29154 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29159 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29160 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29162 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29163 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);
29167 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29172 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29173 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29175 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29176 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);
29180 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);
29185 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29186 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29188 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29189 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29193 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);
29200 this.previewEl.appendChild(this.canvasEl);
29202 this.setCanvasPosition();
29207 if(!this.canvasLoaded){
29211 var imageCanvas = document.createElement("canvas");
29213 var imageContext = imageCanvas.getContext("2d");
29215 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29216 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29218 var center = imageCanvas.width / 2;
29220 imageContext.translate(center, center);
29222 imageContext.rotate(this.rotate * Math.PI / 180);
29224 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29226 var canvas = document.createElement("canvas");
29228 var context = canvas.getContext("2d");
29230 canvas.width = this.minWidth;
29231 canvas.height = this.minHeight;
29233 switch (this.rotate) {
29236 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
29237 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
29239 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29240 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29242 var targetWidth = this.minWidth - 2 * x;
29243 var targetHeight = this.minHeight - 2 * y;
29247 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29248 scale = targetWidth / width;
29251 if(x > 0 && y == 0){
29252 scale = targetHeight / height;
29255 if(x > 0 && y > 0){
29256 scale = targetWidth / width;
29258 if(width < height){
29259 scale = targetHeight / height;
29263 context.scale(scale, scale);
29265 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29266 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29268 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29269 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29271 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29276 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
29277 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
29279 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29280 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29282 var targetWidth = this.minWidth - 2 * x;
29283 var targetHeight = this.minHeight - 2 * y;
29287 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29288 scale = targetWidth / width;
29291 if(x > 0 && y == 0){
29292 scale = targetHeight / height;
29295 if(x > 0 && y > 0){
29296 scale = targetWidth / width;
29298 if(width < height){
29299 scale = targetHeight / height;
29303 context.scale(scale, scale);
29305 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29306 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29308 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29309 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29311 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
29313 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29318 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
29319 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
29321 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29322 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29324 var targetWidth = this.minWidth - 2 * x;
29325 var targetHeight = this.minHeight - 2 * y;
29329 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29330 scale = targetWidth / width;
29333 if(x > 0 && y == 0){
29334 scale = targetHeight / height;
29337 if(x > 0 && y > 0){
29338 scale = targetWidth / width;
29340 if(width < height){
29341 scale = targetHeight / height;
29345 context.scale(scale, scale);
29347 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29348 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29350 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29351 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29353 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
29354 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
29356 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29361 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
29362 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
29364 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29365 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29367 var targetWidth = this.minWidth - 2 * x;
29368 var targetHeight = this.minHeight - 2 * y;
29372 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29373 scale = targetWidth / width;
29376 if(x > 0 && y == 0){
29377 scale = targetHeight / height;
29380 if(x > 0 && y > 0){
29381 scale = targetWidth / width;
29383 if(width < height){
29384 scale = targetHeight / height;
29388 context.scale(scale, scale);
29390 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29391 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29393 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29394 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29396 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
29398 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29405 this.cropData = canvas.toDataURL(this.cropType);
29407 if(this.fireEvent('crop', this, this.cropData) !== false){
29408 this.process(this.file, this.cropData);
29415 setThumbBoxSize : function()
29419 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
29420 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
29421 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
29423 this.minWidth = width;
29424 this.minHeight = height;
29426 if(this.rotate == 90 || this.rotate == 270){
29427 this.minWidth = height;
29428 this.minHeight = width;
29433 width = Math.ceil(this.minWidth * height / this.minHeight);
29435 if(this.minWidth > this.minHeight){
29437 height = Math.ceil(this.minHeight * width / this.minWidth);
29440 this.thumbEl.setStyle({
29441 width : width + 'px',
29442 height : height + 'px'
29449 setThumbBoxPosition : function()
29451 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
29452 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
29454 this.thumbEl.setLeft(x);
29455 this.thumbEl.setTop(y);
29459 baseRotateLevel : function()
29461 this.baseRotate = 1;
29464 typeof(this.exif) != 'undefined' &&
29465 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
29466 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
29468 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
29471 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
29475 baseScaleLevel : function()
29479 if(this.isDocument){
29481 if(this.baseRotate == 6 || this.baseRotate == 8){
29483 height = this.thumbEl.getHeight();
29484 this.baseScale = height / this.imageEl.OriginWidth;
29486 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
29487 width = this.thumbEl.getWidth();
29488 this.baseScale = width / this.imageEl.OriginHeight;
29494 height = this.thumbEl.getHeight();
29495 this.baseScale = height / this.imageEl.OriginHeight;
29497 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
29498 width = this.thumbEl.getWidth();
29499 this.baseScale = width / this.imageEl.OriginWidth;
29505 if(this.baseRotate == 6 || this.baseRotate == 8){
29507 width = this.thumbEl.getHeight();
29508 this.baseScale = width / this.imageEl.OriginHeight;
29510 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
29511 height = this.thumbEl.getWidth();
29512 this.baseScale = height / this.imageEl.OriginHeight;
29515 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29516 height = this.thumbEl.getWidth();
29517 this.baseScale = height / this.imageEl.OriginHeight;
29519 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
29520 width = this.thumbEl.getHeight();
29521 this.baseScale = width / this.imageEl.OriginWidth;
29528 width = this.thumbEl.getWidth();
29529 this.baseScale = width / this.imageEl.OriginWidth;
29531 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
29532 height = this.thumbEl.getHeight();
29533 this.baseScale = height / this.imageEl.OriginHeight;
29536 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29538 height = this.thumbEl.getHeight();
29539 this.baseScale = height / this.imageEl.OriginHeight;
29541 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
29542 width = this.thumbEl.getWidth();
29543 this.baseScale = width / this.imageEl.OriginWidth;
29551 getScaleLevel : function()
29553 return this.baseScale * Math.pow(1.1, this.scale);
29556 onTouchStart : function(e)
29558 if(!this.canvasLoaded){
29559 this.beforeSelectFile(e);
29563 var touches = e.browserEvent.touches;
29569 if(touches.length == 1){
29570 this.onMouseDown(e);
29574 if(touches.length != 2){
29580 for(var i = 0, finger; finger = touches[i]; i++){
29581 coords.push(finger.pageX, finger.pageY);
29584 var x = Math.pow(coords[0] - coords[2], 2);
29585 var y = Math.pow(coords[1] - coords[3], 2);
29587 this.startDistance = Math.sqrt(x + y);
29589 this.startScale = this.scale;
29591 this.pinching = true;
29592 this.dragable = false;
29596 onTouchMove : function(e)
29598 if(!this.pinching && !this.dragable){
29602 var touches = e.browserEvent.touches;
29609 this.onMouseMove(e);
29615 for(var i = 0, finger; finger = touches[i]; i++){
29616 coords.push(finger.pageX, finger.pageY);
29619 var x = Math.pow(coords[0] - coords[2], 2);
29620 var y = Math.pow(coords[1] - coords[3], 2);
29622 this.endDistance = Math.sqrt(x + y);
29624 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
29626 if(!this.zoomable()){
29627 this.scale = this.startScale;
29635 onTouchEnd : function(e)
29637 this.pinching = false;
29638 this.dragable = false;
29642 process : function(file, crop)
29645 this.maskEl.mask(this.loadingText);
29648 this.xhr = new XMLHttpRequest();
29650 file.xhr = this.xhr;
29652 this.xhr.open(this.method, this.url, true);
29655 "Accept": "application/json",
29656 "Cache-Control": "no-cache",
29657 "X-Requested-With": "XMLHttpRequest"
29660 for (var headerName in headers) {
29661 var headerValue = headers[headerName];
29663 this.xhr.setRequestHeader(headerName, headerValue);
29669 this.xhr.onload = function()
29671 _this.xhrOnLoad(_this.xhr);
29674 this.xhr.onerror = function()
29676 _this.xhrOnError(_this.xhr);
29679 var formData = new FormData();
29681 formData.append('returnHTML', 'NO');
29684 formData.append('crop', crop);
29687 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
29688 formData.append(this.paramName, file, file.name);
29691 if(typeof(file.filename) != 'undefined'){
29692 formData.append('filename', file.filename);
29695 if(typeof(file.mimetype) != 'undefined'){
29696 formData.append('mimetype', file.mimetype);
29699 if(this.fireEvent('arrange', this, formData) != false){
29700 this.xhr.send(formData);
29704 xhrOnLoad : function(xhr)
29707 this.maskEl.unmask();
29710 if (xhr.readyState !== 4) {
29711 this.fireEvent('exception', this, xhr);
29715 var response = Roo.decode(xhr.responseText);
29717 if(!response.success){
29718 this.fireEvent('exception', this, xhr);
29722 var response = Roo.decode(xhr.responseText);
29724 this.fireEvent('upload', this, response);
29728 xhrOnError : function()
29731 this.maskEl.unmask();
29734 Roo.log('xhr on error');
29736 var response = Roo.decode(xhr.responseText);
29742 prepare : function(file)
29745 this.maskEl.mask(this.loadingText);
29751 if(typeof(file) === 'string'){
29752 this.loadCanvas(file);
29756 if(!file || !this.urlAPI){
29761 this.cropType = file.type;
29765 if(this.fireEvent('prepare', this, this.file) != false){
29767 var reader = new FileReader();
29769 reader.onload = function (e) {
29770 if (e.target.error) {
29771 Roo.log(e.target.error);
29775 var buffer = e.target.result,
29776 dataView = new DataView(buffer),
29778 maxOffset = dataView.byteLength - 4,
29782 if (dataView.getUint16(0) === 0xffd8) {
29783 while (offset < maxOffset) {
29784 markerBytes = dataView.getUint16(offset);
29786 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
29787 markerLength = dataView.getUint16(offset + 2) + 2;
29788 if (offset + markerLength > dataView.byteLength) {
29789 Roo.log('Invalid meta data: Invalid segment size.');
29793 if(markerBytes == 0xffe1){
29794 _this.parseExifData(
29801 offset += markerLength;
29811 var url = _this.urlAPI.createObjectURL(_this.file);
29813 _this.loadCanvas(url);
29818 reader.readAsArrayBuffer(this.file);
29824 parseExifData : function(dataView, offset, length)
29826 var tiffOffset = offset + 10,
29830 if (dataView.getUint32(offset + 4) !== 0x45786966) {
29831 // No Exif data, might be XMP data instead
29835 // Check for the ASCII code for "Exif" (0x45786966):
29836 if (dataView.getUint32(offset + 4) !== 0x45786966) {
29837 // No Exif data, might be XMP data instead
29840 if (tiffOffset + 8 > dataView.byteLength) {
29841 Roo.log('Invalid Exif data: Invalid segment size.');
29844 // Check for the two null bytes:
29845 if (dataView.getUint16(offset + 8) !== 0x0000) {
29846 Roo.log('Invalid Exif data: Missing byte alignment offset.');
29849 // Check the byte alignment:
29850 switch (dataView.getUint16(tiffOffset)) {
29852 littleEndian = true;
29855 littleEndian = false;
29858 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
29861 // Check for the TIFF tag marker (0x002A):
29862 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
29863 Roo.log('Invalid Exif data: Missing TIFF marker.');
29866 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
29867 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
29869 this.parseExifTags(
29872 tiffOffset + dirOffset,
29877 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
29882 if (dirOffset + 6 > dataView.byteLength) {
29883 Roo.log('Invalid Exif data: Invalid directory offset.');
29886 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
29887 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
29888 if (dirEndOffset + 4 > dataView.byteLength) {
29889 Roo.log('Invalid Exif data: Invalid directory size.');
29892 for (i = 0; i < tagsNumber; i += 1) {
29896 dirOffset + 2 + 12 * i, // tag offset
29900 // Return the offset to the next directory:
29901 return dataView.getUint32(dirEndOffset, littleEndian);
29904 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
29906 var tag = dataView.getUint16(offset, littleEndian);
29908 this.exif[tag] = this.getExifValue(
29912 dataView.getUint16(offset + 2, littleEndian), // tag type
29913 dataView.getUint32(offset + 4, littleEndian), // tag length
29918 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
29920 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
29929 Roo.log('Invalid Exif data: Invalid tag type.');
29933 tagSize = tagType.size * length;
29934 // Determine if the value is contained in the dataOffset bytes,
29935 // or if the value at the dataOffset is a pointer to the actual data:
29936 dataOffset = tagSize > 4 ?
29937 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
29938 if (dataOffset + tagSize > dataView.byteLength) {
29939 Roo.log('Invalid Exif data: Invalid data offset.');
29942 if (length === 1) {
29943 return tagType.getValue(dataView, dataOffset, littleEndian);
29946 for (i = 0; i < length; i += 1) {
29947 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
29950 if (tagType.ascii) {
29952 // Concatenate the chars:
29953 for (i = 0; i < values.length; i += 1) {
29955 // Ignore the terminating NULL byte(s):
29956 if (c === '\u0000') {
29968 Roo.apply(Roo.bootstrap.UploadCropbox, {
29970 'Orientation': 0x0112
29974 1: 0, //'top-left',
29976 3: 180, //'bottom-right',
29977 // 4: 'bottom-left',
29979 6: 90, //'right-top',
29980 // 7: 'right-bottom',
29981 8: 270 //'left-bottom'
29985 // byte, 8-bit unsigned int:
29987 getValue: function (dataView, dataOffset) {
29988 return dataView.getUint8(dataOffset);
29992 // ascii, 8-bit byte:
29994 getValue: function (dataView, dataOffset) {
29995 return String.fromCharCode(dataView.getUint8(dataOffset));
30000 // short, 16 bit int:
30002 getValue: function (dataView, dataOffset, littleEndian) {
30003 return dataView.getUint16(dataOffset, littleEndian);
30007 // long, 32 bit int:
30009 getValue: function (dataView, dataOffset, littleEndian) {
30010 return dataView.getUint32(dataOffset, littleEndian);
30014 // rational = two long values, first is numerator, second is denominator:
30016 getValue: function (dataView, dataOffset, littleEndian) {
30017 return dataView.getUint32(dataOffset, littleEndian) /
30018 dataView.getUint32(dataOffset + 4, littleEndian);
30022 // slong, 32 bit signed int:
30024 getValue: function (dataView, dataOffset, littleEndian) {
30025 return dataView.getInt32(dataOffset, littleEndian);
30029 // srational, two slongs, first is numerator, second is denominator:
30031 getValue: function (dataView, dataOffset, littleEndian) {
30032 return dataView.getInt32(dataOffset, littleEndian) /
30033 dataView.getInt32(dataOffset + 4, littleEndian);
30043 cls : 'btn-group roo-upload-cropbox-rotate-left',
30044 action : 'rotate-left',
30048 cls : 'btn btn-default',
30049 html : '<i class="fa fa-undo"></i>'
30055 cls : 'btn-group roo-upload-cropbox-picture',
30056 action : 'picture',
30060 cls : 'btn btn-default',
30061 html : '<i class="fa fa-picture-o"></i>'
30067 cls : 'btn-group roo-upload-cropbox-rotate-right',
30068 action : 'rotate-right',
30072 cls : 'btn btn-default',
30073 html : '<i class="fa fa-repeat"></i>'
30081 cls : 'btn-group roo-upload-cropbox-rotate-left',
30082 action : 'rotate-left',
30086 cls : 'btn btn-default',
30087 html : '<i class="fa fa-undo"></i>'
30093 cls : 'btn-group roo-upload-cropbox-download',
30094 action : 'download',
30098 cls : 'btn btn-default',
30099 html : '<i class="fa fa-download"></i>'
30105 cls : 'btn-group roo-upload-cropbox-crop',
30110 cls : 'btn btn-default',
30111 html : '<i class="fa fa-crop"></i>'
30117 cls : 'btn-group roo-upload-cropbox-trash',
30122 cls : 'btn btn-default',
30123 html : '<i class="fa fa-trash"></i>'
30129 cls : 'btn-group roo-upload-cropbox-rotate-right',
30130 action : 'rotate-right',
30134 cls : 'btn btn-default',
30135 html : '<i class="fa fa-repeat"></i>'
30143 cls : 'btn-group roo-upload-cropbox-rotate-left',
30144 action : 'rotate-left',
30148 cls : 'btn btn-default',
30149 html : '<i class="fa fa-undo"></i>'
30155 cls : 'btn-group roo-upload-cropbox-rotate-right',
30156 action : 'rotate-right',
30160 cls : 'btn btn-default',
30161 html : '<i class="fa fa-repeat"></i>'
30174 * @class Roo.bootstrap.DocumentManager
30175 * @extends Roo.bootstrap.Component
30176 * Bootstrap DocumentManager class
30177 * @cfg {String} paramName default 'imageUpload'
30178 * @cfg {String} toolTipName default 'filename'
30179 * @cfg {String} method default POST
30180 * @cfg {String} url action url
30181 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
30182 * @cfg {Boolean} multiple multiple upload default true
30183 * @cfg {Number} thumbSize default 300
30184 * @cfg {String} fieldLabel
30185 * @cfg {Number} labelWidth default 4
30186 * @cfg {String} labelAlign (left|top) default left
30187 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
30188 * @cfg {Number} labellg set the width of label (1-12)
30189 * @cfg {Number} labelmd set the width of label (1-12)
30190 * @cfg {Number} labelsm set the width of label (1-12)
30191 * @cfg {Number} labelxs set the width of label (1-12)
30194 * Create a new DocumentManager
30195 * @param {Object} config The config object
30198 Roo.bootstrap.DocumentManager = function(config){
30199 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
30202 this.delegates = [];
30207 * Fire when initial the DocumentManager
30208 * @param {Roo.bootstrap.DocumentManager} this
30213 * inspect selected file
30214 * @param {Roo.bootstrap.DocumentManager} this
30215 * @param {File} file
30220 * Fire when xhr load exception
30221 * @param {Roo.bootstrap.DocumentManager} this
30222 * @param {XMLHttpRequest} xhr
30224 "exception" : true,
30226 * @event afterupload
30227 * Fire when xhr load exception
30228 * @param {Roo.bootstrap.DocumentManager} this
30229 * @param {XMLHttpRequest} xhr
30231 "afterupload" : true,
30234 * prepare the form data
30235 * @param {Roo.bootstrap.DocumentManager} this
30236 * @param {Object} formData
30241 * Fire when remove the file
30242 * @param {Roo.bootstrap.DocumentManager} this
30243 * @param {Object} file
30248 * Fire after refresh the file
30249 * @param {Roo.bootstrap.DocumentManager} this
30254 * Fire after click the image
30255 * @param {Roo.bootstrap.DocumentManager} this
30256 * @param {Object} file
30261 * Fire when upload a image and editable set to true
30262 * @param {Roo.bootstrap.DocumentManager} this
30263 * @param {Object} file
30267 * @event beforeselectfile
30268 * Fire before select file
30269 * @param {Roo.bootstrap.DocumentManager} this
30271 "beforeselectfile" : true,
30274 * Fire before process file
30275 * @param {Roo.bootstrap.DocumentManager} this
30276 * @param {Object} file
30280 * @event previewrendered
30281 * Fire when preview rendered
30282 * @param {Roo.bootstrap.DocumentManager} this
30283 * @param {Object} file
30285 "previewrendered" : true,
30288 "previewResize" : true
30293 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
30302 paramName : 'imageUpload',
30303 toolTipName : 'filename',
30306 labelAlign : 'left',
30316 getAutoCreate : function()
30318 var managerWidget = {
30320 cls : 'roo-document-manager',
30324 cls : 'roo-document-manager-selector',
30329 cls : 'roo-document-manager-uploader',
30333 cls : 'roo-document-manager-upload-btn',
30334 html : '<i class="fa fa-plus"></i>'
30345 cls : 'column col-md-12',
30350 if(this.fieldLabel.length){
30355 cls : 'column col-md-12',
30356 html : this.fieldLabel
30360 cls : 'column col-md-12',
30365 if(this.labelAlign == 'left'){
30370 html : this.fieldLabel
30379 if(this.labelWidth > 12){
30380 content[0].style = "width: " + this.labelWidth + 'px';
30383 if(this.labelWidth < 13 && this.labelmd == 0){
30384 this.labelmd = this.labelWidth;
30387 if(this.labellg > 0){
30388 content[0].cls += ' col-lg-' + this.labellg;
30389 content[1].cls += ' col-lg-' + (12 - this.labellg);
30392 if(this.labelmd > 0){
30393 content[0].cls += ' col-md-' + this.labelmd;
30394 content[1].cls += ' col-md-' + (12 - this.labelmd);
30397 if(this.labelsm > 0){
30398 content[0].cls += ' col-sm-' + this.labelsm;
30399 content[1].cls += ' col-sm-' + (12 - this.labelsm);
30402 if(this.labelxs > 0){
30403 content[0].cls += ' col-xs-' + this.labelxs;
30404 content[1].cls += ' col-xs-' + (12 - this.labelxs);
30412 cls : 'row clearfix',
30420 initEvents : function()
30422 this.managerEl = this.el.select('.roo-document-manager', true).first();
30423 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30425 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
30426 this.selectorEl.hide();
30429 this.selectorEl.attr('multiple', 'multiple');
30432 this.selectorEl.on('change', this.onFileSelected, this);
30434 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
30435 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30437 this.uploader.on('click', this.onUploaderClick, this);
30439 this.renderProgressDialog();
30443 window.addEventListener("resize", function() { _this.refresh(); } );
30445 this.fireEvent('initial', this);
30448 renderProgressDialog : function()
30452 this.progressDialog = new Roo.bootstrap.Modal({
30453 cls : 'roo-document-manager-progress-dialog',
30454 allow_close : false,
30465 btnclick : function() {
30466 _this.uploadCancel();
30472 this.progressDialog.render(Roo.get(document.body));
30474 this.progress = new Roo.bootstrap.Progress({
30475 cls : 'roo-document-manager-progress',
30480 this.progress.render(this.progressDialog.getChildContainer());
30482 this.progressBar = new Roo.bootstrap.ProgressBar({
30483 cls : 'roo-document-manager-progress-bar',
30486 aria_valuemax : 12,
30490 this.progressBar.render(this.progress.getChildContainer());
30493 onUploaderClick : function(e)
30495 e.preventDefault();
30497 if(this.fireEvent('beforeselectfile', this) != false){
30498 this.selectorEl.dom.click();
30503 onFileSelected : function(e)
30505 e.preventDefault();
30507 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
30511 Roo.each(this.selectorEl.dom.files, function(file){
30512 if(this.fireEvent('inspect', this, file) != false){
30513 this.files.push(file);
30523 this.selectorEl.dom.value = '';
30525 if(!this.files || !this.files.length){
30529 if(this.boxes > 0 && this.files.length > this.boxes){
30530 this.files = this.files.slice(0, this.boxes);
30533 this.uploader.show();
30535 if(this.boxes > 0 && this.files.length > this.boxes - 1){
30536 this.uploader.hide();
30545 Roo.each(this.files, function(file){
30547 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
30548 var f = this.renderPreview(file);
30553 if(file.type.indexOf('image') != -1){
30554 this.delegates.push(
30556 _this.process(file);
30557 }).createDelegate(this)
30565 _this.process(file);
30566 }).createDelegate(this)
30571 this.files = files;
30573 this.delegates = this.delegates.concat(docs);
30575 if(!this.delegates.length){
30580 this.progressBar.aria_valuemax = this.delegates.length;
30587 arrange : function()
30589 if(!this.delegates.length){
30590 this.progressDialog.hide();
30595 var delegate = this.delegates.shift();
30597 this.progressDialog.show();
30599 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
30601 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
30606 refresh : function()
30608 this.uploader.show();
30610 if(this.boxes > 0 && this.files.length > this.boxes - 1){
30611 this.uploader.hide();
30614 Roo.isTouch ? this.closable(false) : this.closable(true);
30616 this.fireEvent('refresh', this);
30619 onRemove : function(e, el, o)
30621 e.preventDefault();
30623 this.fireEvent('remove', this, o);
30627 remove : function(o)
30631 Roo.each(this.files, function(file){
30632 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
30641 this.files = files;
30648 Roo.each(this.files, function(file){
30653 file.target.remove();
30662 onClick : function(e, el, o)
30664 e.preventDefault();
30666 this.fireEvent('click', this, o);
30670 closable : function(closable)
30672 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
30674 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30686 xhrOnLoad : function(xhr)
30688 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
30692 if (xhr.readyState !== 4) {
30694 this.fireEvent('exception', this, xhr);
30698 var response = Roo.decode(xhr.responseText);
30700 if(!response.success){
30702 this.fireEvent('exception', this, xhr);
30706 var file = this.renderPreview(response.data);
30708 this.files.push(file);
30712 this.fireEvent('afterupload', this, xhr);
30716 xhrOnError : function(xhr)
30718 Roo.log('xhr on error');
30720 var response = Roo.decode(xhr.responseText);
30727 process : function(file)
30729 if(this.fireEvent('process', this, file) !== false){
30730 if(this.editable && file.type.indexOf('image') != -1){
30731 this.fireEvent('edit', this, file);
30735 this.uploadStart(file, false);
30742 uploadStart : function(file, crop)
30744 this.xhr = new XMLHttpRequest();
30746 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
30751 file.xhr = this.xhr;
30753 this.managerEl.createChild({
30755 cls : 'roo-document-manager-loading',
30759 tooltip : file.name,
30760 cls : 'roo-document-manager-thumb',
30761 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
30767 this.xhr.open(this.method, this.url, true);
30770 "Accept": "application/json",
30771 "Cache-Control": "no-cache",
30772 "X-Requested-With": "XMLHttpRequest"
30775 for (var headerName in headers) {
30776 var headerValue = headers[headerName];
30778 this.xhr.setRequestHeader(headerName, headerValue);
30784 this.xhr.onload = function()
30786 _this.xhrOnLoad(_this.xhr);
30789 this.xhr.onerror = function()
30791 _this.xhrOnError(_this.xhr);
30794 var formData = new FormData();
30796 formData.append('returnHTML', 'NO');
30799 formData.append('crop', crop);
30802 formData.append(this.paramName, file, file.name);
30809 if(this.fireEvent('prepare', this, formData, options) != false){
30811 if(options.manually){
30815 this.xhr.send(formData);
30819 this.uploadCancel();
30822 uploadCancel : function()
30828 this.delegates = [];
30830 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
30837 renderPreview : function(file)
30839 if(typeof(file.target) != 'undefined' && file.target){
30843 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
30845 var previewEl = this.managerEl.createChild({
30847 cls : 'roo-document-manager-preview',
30851 tooltip : file[this.toolTipName],
30852 cls : 'roo-document-manager-thumb',
30853 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
30858 html : '<i class="fa fa-times-circle"></i>'
30863 var close = previewEl.select('button.close', true).first();
30865 close.on('click', this.onRemove, this, file);
30867 file.target = previewEl;
30869 var image = previewEl.select('img', true).first();
30873 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
30875 image.on('click', this.onClick, this, file);
30877 this.fireEvent('previewrendered', this, file);
30883 onPreviewLoad : function(file, image)
30885 if(typeof(file.target) == 'undefined' || !file.target){
30889 var width = image.dom.naturalWidth || image.dom.width;
30890 var height = image.dom.naturalHeight || image.dom.height;
30892 if(!this.previewResize) {
30896 if(width > height){
30897 file.target.addClass('wide');
30901 file.target.addClass('tall');
30906 uploadFromSource : function(file, crop)
30908 this.xhr = new XMLHttpRequest();
30910 this.managerEl.createChild({
30912 cls : 'roo-document-manager-loading',
30916 tooltip : file.name,
30917 cls : 'roo-document-manager-thumb',
30918 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
30924 this.xhr.open(this.method, this.url, true);
30927 "Accept": "application/json",
30928 "Cache-Control": "no-cache",
30929 "X-Requested-With": "XMLHttpRequest"
30932 for (var headerName in headers) {
30933 var headerValue = headers[headerName];
30935 this.xhr.setRequestHeader(headerName, headerValue);
30941 this.xhr.onload = function()
30943 _this.xhrOnLoad(_this.xhr);
30946 this.xhr.onerror = function()
30948 _this.xhrOnError(_this.xhr);
30951 var formData = new FormData();
30953 formData.append('returnHTML', 'NO');
30955 formData.append('crop', crop);
30957 if(typeof(file.filename) != 'undefined'){
30958 formData.append('filename', file.filename);
30961 if(typeof(file.mimetype) != 'undefined'){
30962 formData.append('mimetype', file.mimetype);
30967 if(this.fireEvent('prepare', this, formData) != false){
30968 this.xhr.send(formData);
30978 * @class Roo.bootstrap.DocumentViewer
30979 * @extends Roo.bootstrap.Component
30980 * Bootstrap DocumentViewer class
30981 * @cfg {Boolean} showDownload (true|false) show download button (default true)
30982 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
30985 * Create a new DocumentViewer
30986 * @param {Object} config The config object
30989 Roo.bootstrap.DocumentViewer = function(config){
30990 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
30995 * Fire after initEvent
30996 * @param {Roo.bootstrap.DocumentViewer} this
31002 * @param {Roo.bootstrap.DocumentViewer} this
31007 * Fire after download button
31008 * @param {Roo.bootstrap.DocumentViewer} this
31013 * Fire after trash button
31014 * @param {Roo.bootstrap.DocumentViewer} this
31021 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
31023 showDownload : true,
31027 getAutoCreate : function()
31031 cls : 'roo-document-viewer',
31035 cls : 'roo-document-viewer-body',
31039 cls : 'roo-document-viewer-thumb',
31043 cls : 'roo-document-viewer-image'
31051 cls : 'roo-document-viewer-footer',
31054 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
31058 cls : 'btn-group roo-document-viewer-download',
31062 cls : 'btn btn-default',
31063 html : '<i class="fa fa-download"></i>'
31069 cls : 'btn-group roo-document-viewer-trash',
31073 cls : 'btn btn-default',
31074 html : '<i class="fa fa-trash"></i>'
31087 initEvents : function()
31089 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
31090 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
31092 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
31093 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
31095 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
31096 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
31098 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
31099 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
31101 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
31102 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
31104 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
31105 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
31107 this.bodyEl.on('click', this.onClick, this);
31108 this.downloadBtn.on('click', this.onDownload, this);
31109 this.trashBtn.on('click', this.onTrash, this);
31111 this.downloadBtn.hide();
31112 this.trashBtn.hide();
31114 if(this.showDownload){
31115 this.downloadBtn.show();
31118 if(this.showTrash){
31119 this.trashBtn.show();
31122 if(!this.showDownload && !this.showTrash) {
31123 this.footerEl.hide();
31128 initial : function()
31130 this.fireEvent('initial', this);
31134 onClick : function(e)
31136 e.preventDefault();
31138 this.fireEvent('click', this);
31141 onDownload : function(e)
31143 e.preventDefault();
31145 this.fireEvent('download', this);
31148 onTrash : function(e)
31150 e.preventDefault();
31152 this.fireEvent('trash', this);
31164 * @class Roo.bootstrap.NavProgressBar
31165 * @extends Roo.bootstrap.Component
31166 * Bootstrap NavProgressBar class
31169 * Create a new nav progress bar
31170 * @param {Object} config The config object
31173 Roo.bootstrap.NavProgressBar = function(config){
31174 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
31176 this.bullets = this.bullets || [];
31178 // Roo.bootstrap.NavProgressBar.register(this);
31182 * Fires when the active item changes
31183 * @param {Roo.bootstrap.NavProgressBar} this
31184 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
31185 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
31192 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
31197 getAutoCreate : function()
31199 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
31203 cls : 'roo-navigation-bar-group',
31207 cls : 'roo-navigation-top-bar'
31211 cls : 'roo-navigation-bullets-bar',
31215 cls : 'roo-navigation-bar'
31222 cls : 'roo-navigation-bottom-bar'
31232 initEvents: function()
31237 onRender : function(ct, position)
31239 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
31241 if(this.bullets.length){
31242 Roo.each(this.bullets, function(b){
31251 addItem : function(cfg)
31253 var item = new Roo.bootstrap.NavProgressItem(cfg);
31255 item.parentId = this.id;
31256 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
31259 var top = new Roo.bootstrap.Element({
31261 cls : 'roo-navigation-bar-text'
31264 var bottom = new Roo.bootstrap.Element({
31266 cls : 'roo-navigation-bar-text'
31269 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
31270 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
31272 var topText = new Roo.bootstrap.Element({
31274 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
31277 var bottomText = new Roo.bootstrap.Element({
31279 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
31282 topText.onRender(top.el, null);
31283 bottomText.onRender(bottom.el, null);
31286 item.bottomEl = bottom;
31289 this.barItems.push(item);
31294 getActive : function()
31296 var active = false;
31298 Roo.each(this.barItems, function(v){
31300 if (!v.isActive()) {
31312 setActiveItem : function(item)
31316 Roo.each(this.barItems, function(v){
31317 if (v.rid == item.rid) {
31321 if (v.isActive()) {
31322 v.setActive(false);
31327 item.setActive(true);
31329 this.fireEvent('changed', this, item, prev);
31332 getBarItem: function(rid)
31336 Roo.each(this.barItems, function(e) {
31337 if (e.rid != rid) {
31348 indexOfItem : function(item)
31352 Roo.each(this.barItems, function(v, i){
31354 if (v.rid != item.rid) {
31365 setActiveNext : function()
31367 var i = this.indexOfItem(this.getActive());
31369 if (i > this.barItems.length) {
31373 this.setActiveItem(this.barItems[i+1]);
31376 setActivePrev : function()
31378 var i = this.indexOfItem(this.getActive());
31384 this.setActiveItem(this.barItems[i-1]);
31387 format : function()
31389 if(!this.barItems.length){
31393 var width = 100 / this.barItems.length;
31395 Roo.each(this.barItems, function(i){
31396 i.el.setStyle('width', width + '%');
31397 i.topEl.el.setStyle('width', width + '%');
31398 i.bottomEl.el.setStyle('width', width + '%');
31407 * Nav Progress Item
31412 * @class Roo.bootstrap.NavProgressItem
31413 * @extends Roo.bootstrap.Component
31414 * Bootstrap NavProgressItem class
31415 * @cfg {String} rid the reference id
31416 * @cfg {Boolean} active (true|false) Is item active default false
31417 * @cfg {Boolean} disabled (true|false) Is item active default false
31418 * @cfg {String} html
31419 * @cfg {String} position (top|bottom) text position default bottom
31420 * @cfg {String} icon show icon instead of number
31423 * Create a new NavProgressItem
31424 * @param {Object} config The config object
31426 Roo.bootstrap.NavProgressItem = function(config){
31427 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
31432 * The raw click event for the entire grid.
31433 * @param {Roo.bootstrap.NavProgressItem} this
31434 * @param {Roo.EventObject} e
31441 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
31447 position : 'bottom',
31450 getAutoCreate : function()
31452 var iconCls = 'roo-navigation-bar-item-icon';
31454 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
31458 cls: 'roo-navigation-bar-item',
31468 cfg.cls += ' active';
31471 cfg.cls += ' disabled';
31477 disable : function()
31479 this.setDisabled(true);
31482 enable : function()
31484 this.setDisabled(false);
31487 initEvents: function()
31489 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
31491 this.iconEl.on('click', this.onClick, this);
31494 onClick : function(e)
31496 e.preventDefault();
31502 if(this.fireEvent('click', this, e) === false){
31506 this.parent().setActiveItem(this);
31509 isActive: function ()
31511 return this.active;
31514 setActive : function(state)
31516 if(this.active == state){
31520 this.active = state;
31523 this.el.addClass('active');
31527 this.el.removeClass('active');
31532 setDisabled : function(state)
31534 if(this.disabled == state){
31538 this.disabled = state;
31541 this.el.addClass('disabled');
31545 this.el.removeClass('disabled');
31548 tooltipEl : function()
31550 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
31563 * @class Roo.bootstrap.FieldLabel
31564 * @extends Roo.bootstrap.Component
31565 * Bootstrap FieldLabel class
31566 * @cfg {String} html contents of the element
31567 * @cfg {String} tag tag of the element default label
31568 * @cfg {String} cls class of the element
31569 * @cfg {String} target label target
31570 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
31571 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
31572 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
31573 * @cfg {String} iconTooltip default "This field is required"
31574 * @cfg {String} indicatorpos (left|right) default left
31577 * Create a new FieldLabel
31578 * @param {Object} config The config object
31581 Roo.bootstrap.FieldLabel = function(config){
31582 Roo.bootstrap.Element.superclass.constructor.call(this, config);
31587 * Fires after the field has been marked as invalid.
31588 * @param {Roo.form.FieldLabel} this
31589 * @param {String} msg The validation message
31594 * Fires after the field has been validated with no errors.
31595 * @param {Roo.form.FieldLabel} this
31601 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
31608 invalidClass : 'has-warning',
31609 validClass : 'has-success',
31610 iconTooltip : 'This field is required',
31611 indicatorpos : 'left',
31613 getAutoCreate : function(){
31616 if (!this.allowBlank) {
31622 cls : 'roo-bootstrap-field-label ' + this.cls,
31627 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
31628 tooltip : this.iconTooltip
31637 if(this.indicatorpos == 'right'){
31640 cls : 'roo-bootstrap-field-label ' + this.cls,
31649 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
31650 tooltip : this.iconTooltip
31659 initEvents: function()
31661 Roo.bootstrap.Element.superclass.initEvents.call(this);
31663 this.indicator = this.indicatorEl();
31665 if(this.indicator){
31666 this.indicator.removeClass('visible');
31667 this.indicator.addClass('invisible');
31670 Roo.bootstrap.FieldLabel.register(this);
31673 indicatorEl : function()
31675 var indicator = this.el.select('i.roo-required-indicator',true).first();
31686 * Mark this field as valid
31688 markValid : function()
31690 if(this.indicator){
31691 this.indicator.removeClass('visible');
31692 this.indicator.addClass('invisible');
31694 if (Roo.bootstrap.version == 3) {
31695 this.el.removeClass(this.invalidClass);
31696 this.el.addClass(this.validClass);
31698 this.el.removeClass('is-invalid');
31699 this.el.addClass('is-valid');
31703 this.fireEvent('valid', this);
31707 * Mark this field as invalid
31708 * @param {String} msg The validation message
31710 markInvalid : function(msg)
31712 if(this.indicator){
31713 this.indicator.removeClass('invisible');
31714 this.indicator.addClass('visible');
31716 if (Roo.bootstrap.version == 3) {
31717 this.el.removeClass(this.validClass);
31718 this.el.addClass(this.invalidClass);
31720 this.el.removeClass('is-valid');
31721 this.el.addClass('is-invalid');
31725 this.fireEvent('invalid', this, msg);
31731 Roo.apply(Roo.bootstrap.FieldLabel, {
31736 * register a FieldLabel Group
31737 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
31739 register : function(label)
31741 if(this.groups.hasOwnProperty(label.target)){
31745 this.groups[label.target] = label;
31749 * fetch a FieldLabel Group based on the target
31750 * @param {string} target
31751 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
31753 get: function(target) {
31754 if (typeof(this.groups[target]) == 'undefined') {
31758 return this.groups[target] ;
31767 * page DateSplitField.
31773 * @class Roo.bootstrap.DateSplitField
31774 * @extends Roo.bootstrap.Component
31775 * Bootstrap DateSplitField class
31776 * @cfg {string} fieldLabel - the label associated
31777 * @cfg {Number} labelWidth set the width of label (0-12)
31778 * @cfg {String} labelAlign (top|left)
31779 * @cfg {Boolean} dayAllowBlank (true|false) default false
31780 * @cfg {Boolean} monthAllowBlank (true|false) default false
31781 * @cfg {Boolean} yearAllowBlank (true|false) default false
31782 * @cfg {string} dayPlaceholder
31783 * @cfg {string} monthPlaceholder
31784 * @cfg {string} yearPlaceholder
31785 * @cfg {string} dayFormat default 'd'
31786 * @cfg {string} monthFormat default 'm'
31787 * @cfg {string} yearFormat default 'Y'
31788 * @cfg {Number} labellg set the width of label (1-12)
31789 * @cfg {Number} labelmd set the width of label (1-12)
31790 * @cfg {Number} labelsm set the width of label (1-12)
31791 * @cfg {Number} labelxs set the width of label (1-12)
31795 * Create a new DateSplitField
31796 * @param {Object} config The config object
31799 Roo.bootstrap.DateSplitField = function(config){
31800 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
31806 * getting the data of years
31807 * @param {Roo.bootstrap.DateSplitField} this
31808 * @param {Object} years
31813 * getting the data of days
31814 * @param {Roo.bootstrap.DateSplitField} this
31815 * @param {Object} days
31820 * Fires after the field has been marked as invalid.
31821 * @param {Roo.form.Field} this
31822 * @param {String} msg The validation message
31827 * Fires after the field has been validated with no errors.
31828 * @param {Roo.form.Field} this
31834 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
31837 labelAlign : 'top',
31839 dayAllowBlank : false,
31840 monthAllowBlank : false,
31841 yearAllowBlank : false,
31842 dayPlaceholder : '',
31843 monthPlaceholder : '',
31844 yearPlaceholder : '',
31848 isFormField : true,
31854 getAutoCreate : function()
31858 cls : 'row roo-date-split-field-group',
31863 cls : 'form-hidden-field roo-date-split-field-group-value',
31869 var labelCls = 'col-md-12';
31870 var contentCls = 'col-md-4';
31872 if(this.fieldLabel){
31876 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
31880 html : this.fieldLabel
31885 if(this.labelAlign == 'left'){
31887 if(this.labelWidth > 12){
31888 label.style = "width: " + this.labelWidth + 'px';
31891 if(this.labelWidth < 13 && this.labelmd == 0){
31892 this.labelmd = this.labelWidth;
31895 if(this.labellg > 0){
31896 labelCls = ' col-lg-' + this.labellg;
31897 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
31900 if(this.labelmd > 0){
31901 labelCls = ' col-md-' + this.labelmd;
31902 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
31905 if(this.labelsm > 0){
31906 labelCls = ' col-sm-' + this.labelsm;
31907 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
31910 if(this.labelxs > 0){
31911 labelCls = ' col-xs-' + this.labelxs;
31912 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
31916 label.cls += ' ' + labelCls;
31918 cfg.cn.push(label);
31921 Roo.each(['day', 'month', 'year'], function(t){
31924 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
31931 inputEl: function ()
31933 return this.el.select('.roo-date-split-field-group-value', true).first();
31936 onRender : function(ct, position)
31940 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
31942 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
31944 this.dayField = new Roo.bootstrap.ComboBox({
31945 allowBlank : this.dayAllowBlank,
31946 alwaysQuery : true,
31947 displayField : 'value',
31950 forceSelection : true,
31952 placeholder : this.dayPlaceholder,
31953 selectOnFocus : true,
31954 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
31955 triggerAction : 'all',
31957 valueField : 'value',
31958 store : new Roo.data.SimpleStore({
31959 data : (function() {
31961 _this.fireEvent('days', _this, days);
31964 fields : [ 'value' ]
31967 select : function (_self, record, index)
31969 _this.setValue(_this.getValue());
31974 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
31976 this.monthField = new Roo.bootstrap.MonthField({
31977 after : '<i class=\"fa fa-calendar\"></i>',
31978 allowBlank : this.monthAllowBlank,
31979 placeholder : this.monthPlaceholder,
31982 render : function (_self)
31984 this.el.select('span.input-group-addon', true).first().on('click', function(e){
31985 e.preventDefault();
31989 select : function (_self, oldvalue, newvalue)
31991 _this.setValue(_this.getValue());
31996 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
31998 this.yearField = new Roo.bootstrap.ComboBox({
31999 allowBlank : this.yearAllowBlank,
32000 alwaysQuery : true,
32001 displayField : 'value',
32004 forceSelection : true,
32006 placeholder : this.yearPlaceholder,
32007 selectOnFocus : true,
32008 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32009 triggerAction : 'all',
32011 valueField : 'value',
32012 store : new Roo.data.SimpleStore({
32013 data : (function() {
32015 _this.fireEvent('years', _this, years);
32018 fields : [ 'value' ]
32021 select : function (_self, record, index)
32023 _this.setValue(_this.getValue());
32028 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
32031 setValue : function(v, format)
32033 this.inputEl.dom.value = v;
32035 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
32037 var d = Date.parseDate(v, f);
32044 this.setDay(d.format(this.dayFormat));
32045 this.setMonth(d.format(this.monthFormat));
32046 this.setYear(d.format(this.yearFormat));
32053 setDay : function(v)
32055 this.dayField.setValue(v);
32056 this.inputEl.dom.value = this.getValue();
32061 setMonth : function(v)
32063 this.monthField.setValue(v, true);
32064 this.inputEl.dom.value = this.getValue();
32069 setYear : function(v)
32071 this.yearField.setValue(v);
32072 this.inputEl.dom.value = this.getValue();
32077 getDay : function()
32079 return this.dayField.getValue();
32082 getMonth : function()
32084 return this.monthField.getValue();
32087 getYear : function()
32089 return this.yearField.getValue();
32092 getValue : function()
32094 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
32096 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
32106 this.inputEl.dom.value = '';
32111 validate : function()
32113 var d = this.dayField.validate();
32114 var m = this.monthField.validate();
32115 var y = this.yearField.validate();
32120 (!this.dayAllowBlank && !d) ||
32121 (!this.monthAllowBlank && !m) ||
32122 (!this.yearAllowBlank && !y)
32127 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
32136 this.markInvalid();
32141 markValid : function()
32144 var label = this.el.select('label', true).first();
32145 var icon = this.el.select('i.fa-star', true).first();
32151 this.fireEvent('valid', this);
32155 * Mark this field as invalid
32156 * @param {String} msg The validation message
32158 markInvalid : function(msg)
32161 var label = this.el.select('label', true).first();
32162 var icon = this.el.select('i.fa-star', true).first();
32164 if(label && !icon){
32165 this.el.select('.roo-date-split-field-label', true).createChild({
32167 cls : 'text-danger fa fa-lg fa-star',
32168 tooltip : 'This field is required',
32169 style : 'margin-right:5px;'
32173 this.fireEvent('invalid', this, msg);
32176 clearInvalid : function()
32178 var label = this.el.select('label', true).first();
32179 var icon = this.el.select('i.fa-star', true).first();
32185 this.fireEvent('valid', this);
32188 getName: function()
32198 * http://masonry.desandro.com
32200 * The idea is to render all the bricks based on vertical width...
32202 * The original code extends 'outlayer' - we might need to use that....
32208 * @class Roo.bootstrap.LayoutMasonry
32209 * @extends Roo.bootstrap.Component
32210 * Bootstrap Layout Masonry class
32213 * Create a new Element
32214 * @param {Object} config The config object
32217 Roo.bootstrap.LayoutMasonry = function(config){
32219 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
32223 Roo.bootstrap.LayoutMasonry.register(this);
32229 * Fire after layout the items
32230 * @param {Roo.bootstrap.LayoutMasonry} this
32231 * @param {Roo.EventObject} e
32238 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
32241 * @cfg {Boolean} isLayoutInstant = no animation?
32243 isLayoutInstant : false, // needed?
32246 * @cfg {Number} boxWidth width of the columns
32251 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
32256 * @cfg {Number} padWidth padding below box..
32261 * @cfg {Number} gutter gutter width..
32266 * @cfg {Number} maxCols maximum number of columns
32272 * @cfg {Boolean} isAutoInitial defalut true
32274 isAutoInitial : true,
32279 * @cfg {Boolean} isHorizontal defalut false
32281 isHorizontal : false,
32283 currentSize : null,
32289 bricks: null, //CompositeElement
32293 _isLayoutInited : false,
32295 // isAlternative : false, // only use for vertical layout...
32298 * @cfg {Number} alternativePadWidth padding below box..
32300 alternativePadWidth : 50,
32302 selectedBrick : [],
32304 getAutoCreate : function(){
32306 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
32310 cls: 'blog-masonary-wrapper ' + this.cls,
32312 cls : 'mas-boxes masonary'
32319 getChildContainer: function( )
32321 if (this.boxesEl) {
32322 return this.boxesEl;
32325 this.boxesEl = this.el.select('.mas-boxes').first();
32327 return this.boxesEl;
32331 initEvents : function()
32335 if(this.isAutoInitial){
32336 Roo.log('hook children rendered');
32337 this.on('childrenrendered', function() {
32338 Roo.log('children rendered');
32344 initial : function()
32346 this.selectedBrick = [];
32348 this.currentSize = this.el.getBox(true);
32350 Roo.EventManager.onWindowResize(this.resize, this);
32352 if(!this.isAutoInitial){
32360 //this.layout.defer(500,this);
32364 resize : function()
32366 var cs = this.el.getBox(true);
32369 this.currentSize.width == cs.width &&
32370 this.currentSize.x == cs.x &&
32371 this.currentSize.height == cs.height &&
32372 this.currentSize.y == cs.y
32374 Roo.log("no change in with or X or Y");
32378 this.currentSize = cs;
32384 layout : function()
32386 this._resetLayout();
32388 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32390 this.layoutItems( isInstant );
32392 this._isLayoutInited = true;
32394 this.fireEvent('layout', this);
32398 _resetLayout : function()
32400 if(this.isHorizontal){
32401 this.horizontalMeasureColumns();
32405 this.verticalMeasureColumns();
32409 verticalMeasureColumns : function()
32411 this.getContainerWidth();
32413 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
32414 // this.colWidth = Math.floor(this.containerWidth * 0.8);
32418 var boxWidth = this.boxWidth + this.padWidth;
32420 if(this.containerWidth < this.boxWidth){
32421 boxWidth = this.containerWidth
32424 var containerWidth = this.containerWidth;
32426 var cols = Math.floor(containerWidth / boxWidth);
32428 this.cols = Math.max( cols, 1 );
32430 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32432 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
32434 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
32436 this.colWidth = boxWidth + avail - this.padWidth;
32438 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
32439 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
32442 horizontalMeasureColumns : function()
32444 this.getContainerWidth();
32446 var boxWidth = this.boxWidth;
32448 if(this.containerWidth < boxWidth){
32449 boxWidth = this.containerWidth;
32452 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
32454 this.el.setHeight(boxWidth);
32458 getContainerWidth : function()
32460 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32463 layoutItems : function( isInstant )
32465 Roo.log(this.bricks);
32467 var items = Roo.apply([], this.bricks);
32469 if(this.isHorizontal){
32470 this._horizontalLayoutItems( items , isInstant );
32474 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
32475 // this._verticalAlternativeLayoutItems( items , isInstant );
32479 this._verticalLayoutItems( items , isInstant );
32483 _verticalLayoutItems : function ( items , isInstant)
32485 if ( !items || !items.length ) {
32490 ['xs', 'xs', 'xs', 'tall'],
32491 ['xs', 'xs', 'tall'],
32492 ['xs', 'xs', 'sm'],
32493 ['xs', 'xs', 'xs'],
32499 ['sm', 'xs', 'xs'],
32503 ['tall', 'xs', 'xs', 'xs'],
32504 ['tall', 'xs', 'xs'],
32516 Roo.each(items, function(item, k){
32518 switch (item.size) {
32519 // these layouts take up a full box,
32530 boxes.push([item]);
32553 var filterPattern = function(box, length)
32561 var pattern = box.slice(0, length);
32565 Roo.each(pattern, function(i){
32566 format.push(i.size);
32569 Roo.each(standard, function(s){
32571 if(String(s) != String(format)){
32580 if(!match && length == 1){
32585 filterPattern(box, length - 1);
32589 queue.push(pattern);
32591 box = box.slice(length, box.length);
32593 filterPattern(box, 4);
32599 Roo.each(boxes, function(box, k){
32605 if(box.length == 1){
32610 filterPattern(box, 4);
32614 this._processVerticalLayoutQueue( queue, isInstant );
32618 // _verticalAlternativeLayoutItems : function( items , isInstant )
32620 // if ( !items || !items.length ) {
32624 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
32628 _horizontalLayoutItems : function ( items , isInstant)
32630 if ( !items || !items.length || items.length < 3) {
32636 var eItems = items.slice(0, 3);
32638 items = items.slice(3, items.length);
32641 ['xs', 'xs', 'xs', 'wide'],
32642 ['xs', 'xs', 'wide'],
32643 ['xs', 'xs', 'sm'],
32644 ['xs', 'xs', 'xs'],
32650 ['sm', 'xs', 'xs'],
32654 ['wide', 'xs', 'xs', 'xs'],
32655 ['wide', 'xs', 'xs'],
32668 Roo.each(items, function(item, k){
32670 switch (item.size) {
32681 boxes.push([item]);
32705 var filterPattern = function(box, length)
32713 var pattern = box.slice(0, length);
32717 Roo.each(pattern, function(i){
32718 format.push(i.size);
32721 Roo.each(standard, function(s){
32723 if(String(s) != String(format)){
32732 if(!match && length == 1){
32737 filterPattern(box, length - 1);
32741 queue.push(pattern);
32743 box = box.slice(length, box.length);
32745 filterPattern(box, 4);
32751 Roo.each(boxes, function(box, k){
32757 if(box.length == 1){
32762 filterPattern(box, 4);
32769 var pos = this.el.getBox(true);
32773 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
32775 var hit_end = false;
32777 Roo.each(queue, function(box){
32781 Roo.each(box, function(b){
32783 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32793 Roo.each(box, function(b){
32795 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32798 mx = Math.max(mx, b.x);
32802 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
32806 Roo.each(box, function(b){
32808 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32822 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
32825 /** Sets position of item in DOM
32826 * @param {Element} item
32827 * @param {Number} x - horizontal position
32828 * @param {Number} y - vertical position
32829 * @param {Boolean} isInstant - disables transitions
32831 _processVerticalLayoutQueue : function( queue, isInstant )
32833 var pos = this.el.getBox(true);
32838 for (var i = 0; i < this.cols; i++){
32842 Roo.each(queue, function(box, k){
32844 var col = k % this.cols;
32846 Roo.each(box, function(b,kk){
32848 b.el.position('absolute');
32850 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32851 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32853 if(b.size == 'md-left' || b.size == 'md-right'){
32854 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
32855 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32858 b.el.setWidth(width);
32859 b.el.setHeight(height);
32861 b.el.select('iframe',true).setSize(width,height);
32865 for (var i = 0; i < this.cols; i++){
32867 if(maxY[i] < maxY[col]){
32872 col = Math.min(col, i);
32876 x = pos.x + col * (this.colWidth + this.padWidth);
32880 var positions = [];
32882 switch (box.length){
32884 positions = this.getVerticalOneBoxColPositions(x, y, box);
32887 positions = this.getVerticalTwoBoxColPositions(x, y, box);
32890 positions = this.getVerticalThreeBoxColPositions(x, y, box);
32893 positions = this.getVerticalFourBoxColPositions(x, y, box);
32899 Roo.each(box, function(b,kk){
32901 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
32903 var sz = b.el.getSize();
32905 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
32913 for (var i = 0; i < this.cols; i++){
32914 mY = Math.max(mY, maxY[i]);
32917 this.el.setHeight(mY - pos.y);
32921 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
32923 // var pos = this.el.getBox(true);
32926 // var maxX = pos.right;
32928 // var maxHeight = 0;
32930 // Roo.each(items, function(item, k){
32934 // item.el.position('absolute');
32936 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
32938 // item.el.setWidth(width);
32940 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
32942 // item.el.setHeight(height);
32945 // item.el.setXY([x, y], isInstant ? false : true);
32947 // item.el.setXY([maxX - width, y], isInstant ? false : true);
32950 // y = y + height + this.alternativePadWidth;
32952 // maxHeight = maxHeight + height + this.alternativePadWidth;
32956 // this.el.setHeight(maxHeight);
32960 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
32962 var pos = this.el.getBox(true);
32967 var maxX = pos.right;
32969 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
32971 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
32973 Roo.each(queue, function(box, k){
32975 Roo.each(box, function(b, kk){
32977 b.el.position('absolute');
32979 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32980 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32982 if(b.size == 'md-left' || b.size == 'md-right'){
32983 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
32984 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32987 b.el.setWidth(width);
32988 b.el.setHeight(height);
32996 var positions = [];
32998 switch (box.length){
33000 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
33003 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
33006 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
33009 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
33015 Roo.each(box, function(b,kk){
33017 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33019 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
33027 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
33029 Roo.each(eItems, function(b,k){
33031 b.size = (k == 0) ? 'sm' : 'xs';
33032 b.x = (k == 0) ? 2 : 1;
33033 b.y = (k == 0) ? 2 : 1;
33035 b.el.position('absolute');
33037 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33039 b.el.setWidth(width);
33041 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33043 b.el.setHeight(height);
33047 var positions = [];
33050 x : maxX - this.unitWidth * 2 - this.gutter,
33055 x : maxX - this.unitWidth,
33056 y : minY + (this.unitWidth + this.gutter) * 2
33060 x : maxX - this.unitWidth * 3 - this.gutter * 2,
33064 Roo.each(eItems, function(b,k){
33066 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
33072 getVerticalOneBoxColPositions : function(x, y, box)
33076 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
33078 if(box[0].size == 'md-left'){
33082 if(box[0].size == 'md-right'){
33087 x : x + (this.unitWidth + this.gutter) * rand,
33094 getVerticalTwoBoxColPositions : function(x, y, box)
33098 if(box[0].size == 'xs'){
33102 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
33106 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
33120 x : x + (this.unitWidth + this.gutter) * 2,
33121 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
33128 getVerticalThreeBoxColPositions : function(x, y, box)
33132 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
33140 x : x + (this.unitWidth + this.gutter) * 1,
33145 x : x + (this.unitWidth + this.gutter) * 2,
33153 if(box[0].size == 'xs' && box[1].size == 'xs'){
33162 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
33166 x : x + (this.unitWidth + this.gutter) * 1,
33180 x : x + (this.unitWidth + this.gutter) * 2,
33185 x : x + (this.unitWidth + this.gutter) * 2,
33186 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
33193 getVerticalFourBoxColPositions : function(x, y, box)
33197 if(box[0].size == 'xs'){
33206 y : y + (this.unitHeight + this.gutter) * 1
33211 y : y + (this.unitHeight + this.gutter) * 2
33215 x : x + (this.unitWidth + this.gutter) * 1,
33229 x : x + (this.unitWidth + this.gutter) * 2,
33234 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
33235 y : y + (this.unitHeight + this.gutter) * 1
33239 x : x + (this.unitWidth + this.gutter) * 2,
33240 y : y + (this.unitWidth + this.gutter) * 2
33247 getHorizontalOneBoxColPositions : function(maxX, minY, box)
33251 if(box[0].size == 'md-left'){
33253 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
33260 if(box[0].size == 'md-right'){
33262 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
33263 y : minY + (this.unitWidth + this.gutter) * 1
33269 var rand = Math.floor(Math.random() * (4 - box[0].y));
33272 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33273 y : minY + (this.unitWidth + this.gutter) * rand
33280 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
33284 if(box[0].size == 'xs'){
33287 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33292 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33293 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
33301 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33306 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33307 y : minY + (this.unitWidth + this.gutter) * 2
33314 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
33318 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
33321 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33326 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33327 y : minY + (this.unitWidth + this.gutter) * 1
33331 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33332 y : minY + (this.unitWidth + this.gutter) * 2
33339 if(box[0].size == 'xs' && box[1].size == 'xs'){
33342 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33347 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33352 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33353 y : minY + (this.unitWidth + this.gutter) * 1
33361 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33366 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33367 y : minY + (this.unitWidth + this.gutter) * 2
33371 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33372 y : minY + (this.unitWidth + this.gutter) * 2
33379 getHorizontalFourBoxColPositions : function(maxX, minY, box)
33383 if(box[0].size == 'xs'){
33386 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33391 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33396 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),
33401 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
33402 y : minY + (this.unitWidth + this.gutter) * 1
33410 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33415 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33416 y : minY + (this.unitWidth + this.gutter) * 2
33420 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33421 y : minY + (this.unitWidth + this.gutter) * 2
33425 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),
33426 y : minY + (this.unitWidth + this.gutter) * 2
33434 * remove a Masonry Brick
33435 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
33437 removeBrick : function(brick_id)
33443 for (var i = 0; i<this.bricks.length; i++) {
33444 if (this.bricks[i].id == brick_id) {
33445 this.bricks.splice(i,1);
33446 this.el.dom.removeChild(Roo.get(brick_id).dom);
33453 * adds a Masonry Brick
33454 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33456 addBrick : function(cfg)
33458 var cn = new Roo.bootstrap.MasonryBrick(cfg);
33459 //this.register(cn);
33460 cn.parentId = this.id;
33461 cn.render(this.el);
33466 * register a Masonry Brick
33467 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33470 register : function(brick)
33472 this.bricks.push(brick);
33473 brick.masonryId = this.id;
33477 * clear all the Masonry Brick
33479 clearAll : function()
33482 //this.getChildContainer().dom.innerHTML = "";
33483 this.el.dom.innerHTML = '';
33486 getSelected : function()
33488 if (!this.selectedBrick) {
33492 return this.selectedBrick;
33496 Roo.apply(Roo.bootstrap.LayoutMasonry, {
33500 * register a Masonry Layout
33501 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
33504 register : function(layout)
33506 this.groups[layout.id] = layout;
33509 * fetch a Masonry Layout based on the masonry layout ID
33510 * @param {string} the masonry layout to add
33511 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
33514 get: function(layout_id) {
33515 if (typeof(this.groups[layout_id]) == 'undefined') {
33518 return this.groups[layout_id] ;
33530 * http://masonry.desandro.com
33532 * The idea is to render all the bricks based on vertical width...
33534 * The original code extends 'outlayer' - we might need to use that....
33540 * @class Roo.bootstrap.LayoutMasonryAuto
33541 * @extends Roo.bootstrap.Component
33542 * Bootstrap Layout Masonry class
33545 * Create a new Element
33546 * @param {Object} config The config object
33549 Roo.bootstrap.LayoutMasonryAuto = function(config){
33550 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
33553 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
33556 * @cfg {Boolean} isFitWidth - resize the width..
33558 isFitWidth : false, // options..
33560 * @cfg {Boolean} isOriginLeft = left align?
33562 isOriginLeft : true,
33564 * @cfg {Boolean} isOriginTop = top align?
33566 isOriginTop : false,
33568 * @cfg {Boolean} isLayoutInstant = no animation?
33570 isLayoutInstant : false, // needed?
33572 * @cfg {Boolean} isResizingContainer = not sure if this is used..
33574 isResizingContainer : true,
33576 * @cfg {Number} columnWidth width of the columns
33582 * @cfg {Number} maxCols maximum number of columns
33587 * @cfg {Number} padHeight padding below box..
33593 * @cfg {Boolean} isAutoInitial defalut true
33596 isAutoInitial : true,
33602 initialColumnWidth : 0,
33603 currentSize : null,
33605 colYs : null, // array.
33612 bricks: null, //CompositeElement
33613 cols : 0, // array?
33614 // element : null, // wrapped now this.el
33615 _isLayoutInited : null,
33618 getAutoCreate : function(){
33622 cls: 'blog-masonary-wrapper ' + this.cls,
33624 cls : 'mas-boxes masonary'
33631 getChildContainer: function( )
33633 if (this.boxesEl) {
33634 return this.boxesEl;
33637 this.boxesEl = this.el.select('.mas-boxes').first();
33639 return this.boxesEl;
33643 initEvents : function()
33647 if(this.isAutoInitial){
33648 Roo.log('hook children rendered');
33649 this.on('childrenrendered', function() {
33650 Roo.log('children rendered');
33657 initial : function()
33659 this.reloadItems();
33661 this.currentSize = this.el.getBox(true);
33663 /// was window resize... - let's see if this works..
33664 Roo.EventManager.onWindowResize(this.resize, this);
33666 if(!this.isAutoInitial){
33671 this.layout.defer(500,this);
33674 reloadItems: function()
33676 this.bricks = this.el.select('.masonry-brick', true);
33678 this.bricks.each(function(b) {
33679 //Roo.log(b.getSize());
33680 if (!b.attr('originalwidth')) {
33681 b.attr('originalwidth', b.getSize().width);
33686 Roo.log(this.bricks.elements.length);
33689 resize : function()
33692 var cs = this.el.getBox(true);
33694 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
33695 Roo.log("no change in with or X");
33698 this.currentSize = cs;
33702 layout : function()
33705 this._resetLayout();
33706 //this._manageStamps();
33708 // don't animate first layout
33709 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
33710 this.layoutItems( isInstant );
33712 // flag for initalized
33713 this._isLayoutInited = true;
33716 layoutItems : function( isInstant )
33718 //var items = this._getItemsForLayout( this.items );
33719 // original code supports filtering layout items.. we just ignore it..
33721 this._layoutItems( this.bricks , isInstant );
33723 this._postLayout();
33725 _layoutItems : function ( items , isInstant)
33727 //this.fireEvent( 'layout', this, items );
33730 if ( !items || !items.elements.length ) {
33731 // no items, emit event with empty array
33736 items.each(function(item) {
33737 Roo.log("layout item");
33739 // get x/y object from method
33740 var position = this._getItemLayoutPosition( item );
33742 position.item = item;
33743 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
33744 queue.push( position );
33747 this._processLayoutQueue( queue );
33749 /** Sets position of item in DOM
33750 * @param {Element} item
33751 * @param {Number} x - horizontal position
33752 * @param {Number} y - vertical position
33753 * @param {Boolean} isInstant - disables transitions
33755 _processLayoutQueue : function( queue )
33757 for ( var i=0, len = queue.length; i < len; i++ ) {
33758 var obj = queue[i];
33759 obj.item.position('absolute');
33760 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
33766 * Any logic you want to do after each layout,
33767 * i.e. size the container
33769 _postLayout : function()
33771 this.resizeContainer();
33774 resizeContainer : function()
33776 if ( !this.isResizingContainer ) {
33779 var size = this._getContainerSize();
33781 this.el.setSize(size.width,size.height);
33782 this.boxesEl.setSize(size.width,size.height);
33788 _resetLayout : function()
33790 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
33791 this.colWidth = this.el.getWidth();
33792 //this.gutter = this.el.getWidth();
33794 this.measureColumns();
33800 this.colYs.push( 0 );
33806 measureColumns : function()
33808 this.getContainerWidth();
33809 // if columnWidth is 0, default to outerWidth of first item
33810 if ( !this.columnWidth ) {
33811 var firstItem = this.bricks.first();
33812 Roo.log(firstItem);
33813 this.columnWidth = this.containerWidth;
33814 if (firstItem && firstItem.attr('originalwidth') ) {
33815 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
33817 // columnWidth fall back to item of first element
33818 Roo.log("set column width?");
33819 this.initialColumnWidth = this.columnWidth ;
33821 // if first elem has no width, default to size of container
33826 if (this.initialColumnWidth) {
33827 this.columnWidth = this.initialColumnWidth;
33832 // column width is fixed at the top - however if container width get's smaller we should
33835 // this bit calcs how man columns..
33837 var columnWidth = this.columnWidth += this.gutter;
33839 // calculate columns
33840 var containerWidth = this.containerWidth + this.gutter;
33842 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
33843 // fix rounding errors, typically with gutters
33844 var excess = columnWidth - containerWidth % columnWidth;
33847 // if overshoot is less than a pixel, round up, otherwise floor it
33848 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
33849 cols = Math[ mathMethod ]( cols );
33850 this.cols = Math.max( cols, 1 );
33851 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
33853 // padding positioning..
33854 var totalColWidth = this.cols * this.columnWidth;
33855 var padavail = this.containerWidth - totalColWidth;
33856 // so for 2 columns - we need 3 'pads'
33858 var padNeeded = (1+this.cols) * this.padWidth;
33860 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
33862 this.columnWidth += padExtra
33863 //this.padWidth = Math.floor(padavail / ( this.cols));
33865 // adjust colum width so that padding is fixed??
33867 // we have 3 columns ... total = width * 3
33868 // we have X left over... that should be used by
33870 //if (this.expandC) {
33878 getContainerWidth : function()
33880 /* // container is parent if fit width
33881 var container = this.isFitWidth ? this.element.parentNode : this.element;
33882 // check that this.size and size are there
33883 // IE8 triggers resize on body size change, so they might not be
33885 var size = getSize( container ); //FIXME
33886 this.containerWidth = size && size.innerWidth; //FIXME
33889 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
33893 _getItemLayoutPosition : function( item ) // what is item?
33895 // we resize the item to our columnWidth..
33897 item.setWidth(this.columnWidth);
33898 item.autoBoxAdjust = false;
33900 var sz = item.getSize();
33902 // how many columns does this brick span
33903 var remainder = this.containerWidth % this.columnWidth;
33905 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
33906 // round if off by 1 pixel, otherwise use ceil
33907 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
33908 colSpan = Math.min( colSpan, this.cols );
33910 // normally this should be '1' as we dont' currently allow multi width columns..
33912 var colGroup = this._getColGroup( colSpan );
33913 // get the minimum Y value from the columns
33914 var minimumY = Math.min.apply( Math, colGroup );
33915 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
33917 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
33919 // position the brick
33921 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
33922 y: this.currentSize.y + minimumY + this.padHeight
33926 // apply setHeight to necessary columns
33927 var setHeight = minimumY + sz.height + this.padHeight;
33928 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
33930 var setSpan = this.cols + 1 - colGroup.length;
33931 for ( var i = 0; i < setSpan; i++ ) {
33932 this.colYs[ shortColIndex + i ] = setHeight ;
33939 * @param {Number} colSpan - number of columns the element spans
33940 * @returns {Array} colGroup
33942 _getColGroup : function( colSpan )
33944 if ( colSpan < 2 ) {
33945 // if brick spans only one column, use all the column Ys
33950 // how many different places could this brick fit horizontally
33951 var groupCount = this.cols + 1 - colSpan;
33952 // for each group potential horizontal position
33953 for ( var i = 0; i < groupCount; i++ ) {
33954 // make an array of colY values for that one group
33955 var groupColYs = this.colYs.slice( i, i + colSpan );
33956 // and get the max value of the array
33957 colGroup[i] = Math.max.apply( Math, groupColYs );
33962 _manageStamp : function( stamp )
33964 var stampSize = stamp.getSize();
33965 var offset = stamp.getBox();
33966 // get the columns that this stamp affects
33967 var firstX = this.isOriginLeft ? offset.x : offset.right;
33968 var lastX = firstX + stampSize.width;
33969 var firstCol = Math.floor( firstX / this.columnWidth );
33970 firstCol = Math.max( 0, firstCol );
33972 var lastCol = Math.floor( lastX / this.columnWidth );
33973 // lastCol should not go over if multiple of columnWidth #425
33974 lastCol -= lastX % this.columnWidth ? 0 : 1;
33975 lastCol = Math.min( this.cols - 1, lastCol );
33977 // set colYs to bottom of the stamp
33978 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
33981 for ( var i = firstCol; i <= lastCol; i++ ) {
33982 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
33987 _getContainerSize : function()
33989 this.maxY = Math.max.apply( Math, this.colYs );
33994 if ( this.isFitWidth ) {
33995 size.width = this._getContainerFitWidth();
34001 _getContainerFitWidth : function()
34003 var unusedCols = 0;
34004 // count unused columns
34007 if ( this.colYs[i] !== 0 ) {
34012 // fit container to columns that have been used
34013 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
34016 needsResizeLayout : function()
34018 var previousWidth = this.containerWidth;
34019 this.getContainerWidth();
34020 return previousWidth !== this.containerWidth;
34035 * @class Roo.bootstrap.MasonryBrick
34036 * @extends Roo.bootstrap.Component
34037 * Bootstrap MasonryBrick class
34040 * Create a new MasonryBrick
34041 * @param {Object} config The config object
34044 Roo.bootstrap.MasonryBrick = function(config){
34046 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
34048 Roo.bootstrap.MasonryBrick.register(this);
34054 * When a MasonryBrick is clcik
34055 * @param {Roo.bootstrap.MasonryBrick} this
34056 * @param {Roo.EventObject} e
34062 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
34065 * @cfg {String} title
34069 * @cfg {String} html
34073 * @cfg {String} bgimage
34077 * @cfg {String} videourl
34081 * @cfg {String} cls
34085 * @cfg {String} href
34089 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
34094 * @cfg {String} placetitle (center|bottom)
34099 * @cfg {Boolean} isFitContainer defalut true
34101 isFitContainer : true,
34104 * @cfg {Boolean} preventDefault defalut false
34106 preventDefault : false,
34109 * @cfg {Boolean} inverse defalut false
34111 maskInverse : false,
34113 getAutoCreate : function()
34115 if(!this.isFitContainer){
34116 return this.getSplitAutoCreate();
34119 var cls = 'masonry-brick masonry-brick-full';
34121 if(this.href.length){
34122 cls += ' masonry-brick-link';
34125 if(this.bgimage.length){
34126 cls += ' masonry-brick-image';
34129 if(this.maskInverse){
34130 cls += ' mask-inverse';
34133 if(!this.html.length && !this.maskInverse && !this.videourl.length){
34134 cls += ' enable-mask';
34138 cls += ' masonry-' + this.size + '-brick';
34141 if(this.placetitle.length){
34143 switch (this.placetitle) {
34145 cls += ' masonry-center-title';
34148 cls += ' masonry-bottom-title';
34155 if(!this.html.length && !this.bgimage.length){
34156 cls += ' masonry-center-title';
34159 if(!this.html.length && this.bgimage.length){
34160 cls += ' masonry-bottom-title';
34165 cls += ' ' + this.cls;
34169 tag: (this.href.length) ? 'a' : 'div',
34174 cls: 'masonry-brick-mask'
34178 cls: 'masonry-brick-paragraph',
34184 if(this.href.length){
34185 cfg.href = this.href;
34188 var cn = cfg.cn[1].cn;
34190 if(this.title.length){
34193 cls: 'masonry-brick-title',
34198 if(this.html.length){
34201 cls: 'masonry-brick-text',
34206 if (!this.title.length && !this.html.length) {
34207 cfg.cn[1].cls += ' hide';
34210 if(this.bgimage.length){
34213 cls: 'masonry-brick-image-view',
34218 if(this.videourl.length){
34219 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
34220 // youtube support only?
34223 cls: 'masonry-brick-image-view',
34226 allowfullscreen : true
34234 getSplitAutoCreate : function()
34236 var cls = 'masonry-brick masonry-brick-split';
34238 if(this.href.length){
34239 cls += ' masonry-brick-link';
34242 if(this.bgimage.length){
34243 cls += ' masonry-brick-image';
34247 cls += ' masonry-' + this.size + '-brick';
34250 switch (this.placetitle) {
34252 cls += ' masonry-center-title';
34255 cls += ' masonry-bottom-title';
34258 if(!this.bgimage.length){
34259 cls += ' masonry-center-title';
34262 if(this.bgimage.length){
34263 cls += ' masonry-bottom-title';
34269 cls += ' ' + this.cls;
34273 tag: (this.href.length) ? 'a' : 'div',
34278 cls: 'masonry-brick-split-head',
34282 cls: 'masonry-brick-paragraph',
34289 cls: 'masonry-brick-split-body',
34295 if(this.href.length){
34296 cfg.href = this.href;
34299 if(this.title.length){
34300 cfg.cn[0].cn[0].cn.push({
34302 cls: 'masonry-brick-title',
34307 if(this.html.length){
34308 cfg.cn[1].cn.push({
34310 cls: 'masonry-brick-text',
34315 if(this.bgimage.length){
34316 cfg.cn[0].cn.push({
34318 cls: 'masonry-brick-image-view',
34323 if(this.videourl.length){
34324 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
34325 // youtube support only?
34326 cfg.cn[0].cn.cn.push({
34328 cls: 'masonry-brick-image-view',
34331 allowfullscreen : true
34338 initEvents: function()
34340 switch (this.size) {
34373 this.el.on('touchstart', this.onTouchStart, this);
34374 this.el.on('touchmove', this.onTouchMove, this);
34375 this.el.on('touchend', this.onTouchEnd, this);
34376 this.el.on('contextmenu', this.onContextMenu, this);
34378 this.el.on('mouseenter' ,this.enter, this);
34379 this.el.on('mouseleave', this.leave, this);
34380 this.el.on('click', this.onClick, this);
34383 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
34384 this.parent().bricks.push(this);
34389 onClick: function(e, el)
34391 var time = this.endTimer - this.startTimer;
34392 // Roo.log(e.preventDefault());
34395 e.preventDefault();
34400 if(!this.preventDefault){
34404 e.preventDefault();
34406 if (this.activeClass != '') {
34407 this.selectBrick();
34410 this.fireEvent('click', this, e);
34413 enter: function(e, el)
34415 e.preventDefault();
34417 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
34421 if(this.bgimage.length && this.html.length){
34422 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
34426 leave: function(e, el)
34428 e.preventDefault();
34430 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
34434 if(this.bgimage.length && this.html.length){
34435 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
34439 onTouchStart: function(e, el)
34441 // e.preventDefault();
34443 this.touchmoved = false;
34445 if(!this.isFitContainer){
34449 if(!this.bgimage.length || !this.html.length){
34453 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
34455 this.timer = new Date().getTime();
34459 onTouchMove: function(e, el)
34461 this.touchmoved = true;
34464 onContextMenu : function(e,el)
34466 e.preventDefault();
34467 e.stopPropagation();
34471 onTouchEnd: function(e, el)
34473 // e.preventDefault();
34475 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
34482 if(!this.bgimage.length || !this.html.length){
34484 if(this.href.length){
34485 window.location.href = this.href;
34491 if(!this.isFitContainer){
34495 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
34497 window.location.href = this.href;
34500 //selection on single brick only
34501 selectBrick : function() {
34503 if (!this.parentId) {
34507 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
34508 var index = m.selectedBrick.indexOf(this.id);
34511 m.selectedBrick.splice(index,1);
34512 this.el.removeClass(this.activeClass);
34516 for(var i = 0; i < m.selectedBrick.length; i++) {
34517 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
34518 b.el.removeClass(b.activeClass);
34521 m.selectedBrick = [];
34523 m.selectedBrick.push(this.id);
34524 this.el.addClass(this.activeClass);
34528 isSelected : function(){
34529 return this.el.hasClass(this.activeClass);
34534 Roo.apply(Roo.bootstrap.MasonryBrick, {
34537 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
34539 * register a Masonry Brick
34540 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34543 register : function(brick)
34545 //this.groups[brick.id] = brick;
34546 this.groups.add(brick.id, brick);
34549 * fetch a masonry brick based on the masonry brick ID
34550 * @param {string} the masonry brick to add
34551 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
34554 get: function(brick_id)
34556 // if (typeof(this.groups[brick_id]) == 'undefined') {
34559 // return this.groups[brick_id] ;
34561 if(this.groups.key(brick_id)) {
34562 return this.groups.key(brick_id);
34580 * @class Roo.bootstrap.Brick
34581 * @extends Roo.bootstrap.Component
34582 * Bootstrap Brick class
34585 * Create a new Brick
34586 * @param {Object} config The config object
34589 Roo.bootstrap.Brick = function(config){
34590 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
34596 * When a Brick is click
34597 * @param {Roo.bootstrap.Brick} this
34598 * @param {Roo.EventObject} e
34604 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
34607 * @cfg {String} title
34611 * @cfg {String} html
34615 * @cfg {String} bgimage
34619 * @cfg {String} cls
34623 * @cfg {String} href
34627 * @cfg {String} video
34631 * @cfg {Boolean} square
34635 getAutoCreate : function()
34637 var cls = 'roo-brick';
34639 if(this.href.length){
34640 cls += ' roo-brick-link';
34643 if(this.bgimage.length){
34644 cls += ' roo-brick-image';
34647 if(!this.html.length && !this.bgimage.length){
34648 cls += ' roo-brick-center-title';
34651 if(!this.html.length && this.bgimage.length){
34652 cls += ' roo-brick-bottom-title';
34656 cls += ' ' + this.cls;
34660 tag: (this.href.length) ? 'a' : 'div',
34665 cls: 'roo-brick-paragraph',
34671 if(this.href.length){
34672 cfg.href = this.href;
34675 var cn = cfg.cn[0].cn;
34677 if(this.title.length){
34680 cls: 'roo-brick-title',
34685 if(this.html.length){
34688 cls: 'roo-brick-text',
34695 if(this.bgimage.length){
34698 cls: 'roo-brick-image-view',
34706 initEvents: function()
34708 if(this.title.length || this.html.length){
34709 this.el.on('mouseenter' ,this.enter, this);
34710 this.el.on('mouseleave', this.leave, this);
34713 Roo.EventManager.onWindowResize(this.resize, this);
34715 if(this.bgimage.length){
34716 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
34717 this.imageEl.on('load', this.onImageLoad, this);
34724 onImageLoad : function()
34729 resize : function()
34731 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
34733 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
34735 if(this.bgimage.length){
34736 var image = this.el.select('.roo-brick-image-view', true).first();
34738 image.setWidth(paragraph.getWidth());
34741 image.setHeight(paragraph.getWidth());
34744 this.el.setHeight(image.getHeight());
34745 paragraph.setHeight(image.getHeight());
34751 enter: function(e, el)
34753 e.preventDefault();
34755 if(this.bgimage.length){
34756 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
34757 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
34761 leave: function(e, el)
34763 e.preventDefault();
34765 if(this.bgimage.length){
34766 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
34767 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
34782 * @class Roo.bootstrap.NumberField
34783 * @extends Roo.bootstrap.Input
34784 * Bootstrap NumberField class
34790 * Create a new NumberField
34791 * @param {Object} config The config object
34794 Roo.bootstrap.NumberField = function(config){
34795 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
34798 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
34801 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
34803 allowDecimals : true,
34805 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
34807 decimalSeparator : ".",
34809 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
34811 decimalPrecision : 2,
34813 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
34815 allowNegative : true,
34818 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
34822 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
34824 minValue : Number.NEGATIVE_INFINITY,
34826 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
34828 maxValue : Number.MAX_VALUE,
34830 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
34832 minText : "The minimum value for this field is {0}",
34834 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
34836 maxText : "The maximum value for this field is {0}",
34838 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
34839 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
34841 nanText : "{0} is not a valid number",
34843 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
34845 thousandsDelimiter : false,
34847 * @cfg {String} valueAlign alignment of value
34849 valueAlign : "left",
34851 getAutoCreate : function()
34853 var hiddenInput = {
34857 cls: 'hidden-number-input'
34861 hiddenInput.name = this.name;
34866 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
34868 this.name = hiddenInput.name;
34870 if(cfg.cn.length > 0) {
34871 cfg.cn.push(hiddenInput);
34878 initEvents : function()
34880 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
34882 var allowed = "0123456789";
34884 if(this.allowDecimals){
34885 allowed += this.decimalSeparator;
34888 if(this.allowNegative){
34892 if(this.thousandsDelimiter) {
34896 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
34898 var keyPress = function(e){
34900 var k = e.getKey();
34902 var c = e.getCharCode();
34905 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
34906 allowed.indexOf(String.fromCharCode(c)) === -1
34912 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
34916 if(allowed.indexOf(String.fromCharCode(c)) === -1){
34921 this.el.on("keypress", keyPress, this);
34924 validateValue : function(value)
34927 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
34931 var num = this.parseValue(value);
34934 this.markInvalid(String.format(this.nanText, value));
34938 if(num < this.minValue){
34939 this.markInvalid(String.format(this.minText, this.minValue));
34943 if(num > this.maxValue){
34944 this.markInvalid(String.format(this.maxText, this.maxValue));
34951 getValue : function()
34953 var v = this.hiddenEl().getValue();
34955 return this.fixPrecision(this.parseValue(v));
34958 parseValue : function(value)
34960 if(this.thousandsDelimiter) {
34962 r = new RegExp(",", "g");
34963 value = value.replace(r, "");
34966 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
34967 return isNaN(value) ? '' : value;
34970 fixPrecision : function(value)
34972 if(this.thousandsDelimiter) {
34974 r = new RegExp(",", "g");
34975 value = value.replace(r, "");
34978 var nan = isNaN(value);
34980 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
34981 return nan ? '' : value;
34983 return parseFloat(value).toFixed(this.decimalPrecision);
34986 setValue : function(v)
34988 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
34994 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
34996 this.inputEl().dom.value = (v == '') ? '' :
34997 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
34999 if(!this.allowZero && v === '0') {
35000 this.hiddenEl().dom.value = '';
35001 this.inputEl().dom.value = '';
35008 decimalPrecisionFcn : function(v)
35010 return Math.floor(v);
35013 beforeBlur : function()
35015 var v = this.parseValue(this.getRawValue());
35017 if(v || v === 0 || v === ''){
35022 hiddenEl : function()
35024 return this.el.select('input.hidden-number-input',true).first();
35036 * @class Roo.bootstrap.DocumentSlider
35037 * @extends Roo.bootstrap.Component
35038 * Bootstrap DocumentSlider class
35041 * Create a new DocumentViewer
35042 * @param {Object} config The config object
35045 Roo.bootstrap.DocumentSlider = function(config){
35046 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
35053 * Fire after initEvent
35054 * @param {Roo.bootstrap.DocumentSlider} this
35059 * Fire after update
35060 * @param {Roo.bootstrap.DocumentSlider} this
35066 * @param {Roo.bootstrap.DocumentSlider} this
35072 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
35078 getAutoCreate : function()
35082 cls : 'roo-document-slider',
35086 cls : 'roo-document-slider-header',
35090 cls : 'roo-document-slider-header-title'
35096 cls : 'roo-document-slider-body',
35100 cls : 'roo-document-slider-prev',
35104 cls : 'fa fa-chevron-left'
35110 cls : 'roo-document-slider-thumb',
35114 cls : 'roo-document-slider-image'
35120 cls : 'roo-document-slider-next',
35124 cls : 'fa fa-chevron-right'
35136 initEvents : function()
35138 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
35139 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
35141 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
35142 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
35144 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
35145 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
35147 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
35148 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
35150 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
35151 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
35153 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
35154 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35156 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
35157 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35159 this.thumbEl.on('click', this.onClick, this);
35161 this.prevIndicator.on('click', this.prev, this);
35163 this.nextIndicator.on('click', this.next, this);
35167 initial : function()
35169 if(this.files.length){
35170 this.indicator = 1;
35174 this.fireEvent('initial', this);
35177 update : function()
35179 this.imageEl.attr('src', this.files[this.indicator - 1]);
35181 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
35183 this.prevIndicator.show();
35185 if(this.indicator == 1){
35186 this.prevIndicator.hide();
35189 this.nextIndicator.show();
35191 if(this.indicator == this.files.length){
35192 this.nextIndicator.hide();
35195 this.thumbEl.scrollTo('top');
35197 this.fireEvent('update', this);
35200 onClick : function(e)
35202 e.preventDefault();
35204 this.fireEvent('click', this);
35209 e.preventDefault();
35211 this.indicator = Math.max(1, this.indicator - 1);
35218 e.preventDefault();
35220 this.indicator = Math.min(this.files.length, this.indicator + 1);
35234 * @class Roo.bootstrap.RadioSet
35235 * @extends Roo.bootstrap.Input
35236 * Bootstrap RadioSet class
35237 * @cfg {String} indicatorpos (left|right) default left
35238 * @cfg {Boolean} inline (true|false) inline the element (default true)
35239 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
35241 * Create a new RadioSet
35242 * @param {Object} config The config object
35245 Roo.bootstrap.RadioSet = function(config){
35247 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
35251 Roo.bootstrap.RadioSet.register(this);
35256 * Fires when the element is checked or unchecked.
35257 * @param {Roo.bootstrap.RadioSet} this This radio
35258 * @param {Roo.bootstrap.Radio} item The checked item
35263 * Fires when the element is click.
35264 * @param {Roo.bootstrap.RadioSet} this This radio set
35265 * @param {Roo.bootstrap.Radio} item The checked item
35266 * @param {Roo.EventObject} e The event object
35273 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
35281 indicatorpos : 'left',
35283 getAutoCreate : function()
35287 cls : 'roo-radio-set-label',
35291 html : this.fieldLabel
35295 if (Roo.bootstrap.version == 3) {
35298 if(this.indicatorpos == 'left'){
35301 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
35302 tooltip : 'This field is required'
35307 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
35308 tooltip : 'This field is required'
35314 cls : 'roo-radio-set-items'
35317 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
35319 if (align === 'left' && this.fieldLabel.length) {
35322 cls : "roo-radio-set-right",
35328 if(this.labelWidth > 12){
35329 label.style = "width: " + this.labelWidth + 'px';
35332 if(this.labelWidth < 13 && this.labelmd == 0){
35333 this.labelmd = this.labelWidth;
35336 if(this.labellg > 0){
35337 label.cls += ' col-lg-' + this.labellg;
35338 items.cls += ' col-lg-' + (12 - this.labellg);
35341 if(this.labelmd > 0){
35342 label.cls += ' col-md-' + this.labelmd;
35343 items.cls += ' col-md-' + (12 - this.labelmd);
35346 if(this.labelsm > 0){
35347 label.cls += ' col-sm-' + this.labelsm;
35348 items.cls += ' col-sm-' + (12 - this.labelsm);
35351 if(this.labelxs > 0){
35352 label.cls += ' col-xs-' + this.labelxs;
35353 items.cls += ' col-xs-' + (12 - this.labelxs);
35359 cls : 'roo-radio-set',
35363 cls : 'roo-radio-set-input',
35366 value : this.value ? this.value : ''
35373 if(this.weight.length){
35374 cfg.cls += ' roo-radio-' + this.weight;
35378 cfg.cls += ' roo-radio-set-inline';
35382 ['xs','sm','md','lg'].map(function(size){
35383 if (settings[size]) {
35384 cfg.cls += ' col-' + size + '-' + settings[size];
35392 initEvents : function()
35394 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
35395 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
35397 if(!this.fieldLabel.length){
35398 this.labelEl.hide();
35401 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
35402 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
35404 this.indicator = this.indicatorEl();
35406 if(this.indicator){
35407 this.indicator.addClass('invisible');
35410 this.originalValue = this.getValue();
35414 inputEl: function ()
35416 return this.el.select('.roo-radio-set-input', true).first();
35419 getChildContainer : function()
35421 return this.itemsEl;
35424 register : function(item)
35426 this.radioes.push(item);
35430 validate : function()
35432 if(this.getVisibilityEl().hasClass('hidden')){
35438 Roo.each(this.radioes, function(i){
35447 if(this.allowBlank) {
35451 if(this.disabled || valid){
35456 this.markInvalid();
35461 markValid : function()
35463 if(this.labelEl.isVisible(true) && this.indicatorEl()){
35464 this.indicatorEl().removeClass('visible');
35465 this.indicatorEl().addClass('invisible');
35469 if (Roo.bootstrap.version == 3) {
35470 this.el.removeClass([this.invalidClass, this.validClass]);
35471 this.el.addClass(this.validClass);
35473 this.el.removeClass(['is-invalid','is-valid']);
35474 this.el.addClass(['is-valid']);
35476 this.fireEvent('valid', this);
35479 markInvalid : function(msg)
35481 if(this.allowBlank || this.disabled){
35485 if(this.labelEl.isVisible(true) && this.indicatorEl()){
35486 this.indicatorEl().removeClass('invisible');
35487 this.indicatorEl().addClass('visible');
35489 if (Roo.bootstrap.version == 3) {
35490 this.el.removeClass([this.invalidClass, this.validClass]);
35491 this.el.addClass(this.invalidClass);
35493 this.el.removeClass(['is-invalid','is-valid']);
35494 this.el.addClass(['is-invalid']);
35497 this.fireEvent('invalid', this, msg);
35501 setValue : function(v, suppressEvent)
35503 if(this.value === v){
35510 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
35513 Roo.each(this.radioes, function(i){
35515 i.el.removeClass('checked');
35518 Roo.each(this.radioes, function(i){
35520 if(i.value === v || i.value.toString() === v.toString()){
35522 i.el.addClass('checked');
35524 if(suppressEvent !== true){
35525 this.fireEvent('check', this, i);
35536 clearInvalid : function(){
35538 if(!this.el || this.preventMark){
35542 this.el.removeClass([this.invalidClass]);
35544 this.fireEvent('valid', this);
35549 Roo.apply(Roo.bootstrap.RadioSet, {
35553 register : function(set)
35555 this.groups[set.name] = set;
35558 get: function(name)
35560 if (typeof(this.groups[name]) == 'undefined') {
35564 return this.groups[name] ;
35570 * Ext JS Library 1.1.1
35571 * Copyright(c) 2006-2007, Ext JS, LLC.
35573 * Originally Released Under LGPL - original licence link has changed is not relivant.
35576 * <script type="text/javascript">
35581 * @class Roo.bootstrap.SplitBar
35582 * @extends Roo.util.Observable
35583 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
35587 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
35588 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
35589 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
35590 split.minSize = 100;
35591 split.maxSize = 600;
35592 split.animate = true;
35593 split.on('moved', splitterMoved);
35596 * Create a new SplitBar
35597 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
35598 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
35599 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
35600 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
35601 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
35602 position of the SplitBar).
35604 Roo.bootstrap.SplitBar = function(cfg){
35609 // dragElement : elm
35610 // resizingElement: el,
35612 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
35613 // placement : Roo.bootstrap.SplitBar.LEFT ,
35614 // existingProxy ???
35617 this.el = Roo.get(cfg.dragElement, true);
35618 this.el.dom.unselectable = "on";
35620 this.resizingEl = Roo.get(cfg.resizingElement, true);
35624 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
35625 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
35628 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
35631 * The minimum size of the resizing element. (Defaults to 0)
35637 * The maximum size of the resizing element. (Defaults to 2000)
35640 this.maxSize = 2000;
35643 * Whether to animate the transition to the new size
35646 this.animate = false;
35649 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
35652 this.useShim = false;
35657 if(!cfg.existingProxy){
35659 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
35661 this.proxy = Roo.get(cfg.existingProxy).dom;
35664 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
35667 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
35670 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
35673 this.dragSpecs = {};
35676 * @private The adapter to use to positon and resize elements
35678 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
35679 this.adapter.init(this);
35681 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35683 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
35684 this.el.addClass("roo-splitbar-h");
35687 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
35688 this.el.addClass("roo-splitbar-v");
35694 * Fires when the splitter is moved (alias for {@link #event-moved})
35695 * @param {Roo.bootstrap.SplitBar} this
35696 * @param {Number} newSize the new width or height
35701 * Fires when the splitter is moved
35702 * @param {Roo.bootstrap.SplitBar} this
35703 * @param {Number} newSize the new width or height
35707 * @event beforeresize
35708 * Fires before the splitter is dragged
35709 * @param {Roo.bootstrap.SplitBar} this
35711 "beforeresize" : true,
35713 "beforeapply" : true
35716 Roo.util.Observable.call(this);
35719 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
35720 onStartProxyDrag : function(x, y){
35721 this.fireEvent("beforeresize", this);
35723 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
35725 o.enableDisplayMode("block");
35726 // all splitbars share the same overlay
35727 Roo.bootstrap.SplitBar.prototype.overlay = o;
35729 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
35730 this.overlay.show();
35731 Roo.get(this.proxy).setDisplayed("block");
35732 var size = this.adapter.getElementSize(this);
35733 this.activeMinSize = this.getMinimumSize();;
35734 this.activeMaxSize = this.getMaximumSize();;
35735 var c1 = size - this.activeMinSize;
35736 var c2 = Math.max(this.activeMaxSize - size, 0);
35737 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35738 this.dd.resetConstraints();
35739 this.dd.setXConstraint(
35740 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
35741 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
35743 this.dd.setYConstraint(0, 0);
35745 this.dd.resetConstraints();
35746 this.dd.setXConstraint(0, 0);
35747 this.dd.setYConstraint(
35748 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
35749 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
35752 this.dragSpecs.startSize = size;
35753 this.dragSpecs.startPoint = [x, y];
35754 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
35758 * @private Called after the drag operation by the DDProxy
35760 onEndProxyDrag : function(e){
35761 Roo.get(this.proxy).setDisplayed(false);
35762 var endPoint = Roo.lib.Event.getXY(e);
35764 this.overlay.hide();
35767 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35768 newSize = this.dragSpecs.startSize +
35769 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
35770 endPoint[0] - this.dragSpecs.startPoint[0] :
35771 this.dragSpecs.startPoint[0] - endPoint[0]
35774 newSize = this.dragSpecs.startSize +
35775 (this.placement == Roo.bootstrap.SplitBar.TOP ?
35776 endPoint[1] - this.dragSpecs.startPoint[1] :
35777 this.dragSpecs.startPoint[1] - endPoint[1]
35780 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
35781 if(newSize != this.dragSpecs.startSize){
35782 if(this.fireEvent('beforeapply', this, newSize) !== false){
35783 this.adapter.setElementSize(this, newSize);
35784 this.fireEvent("moved", this, newSize);
35785 this.fireEvent("resize", this, newSize);
35791 * Get the adapter this SplitBar uses
35792 * @return The adapter object
35794 getAdapter : function(){
35795 return this.adapter;
35799 * Set the adapter this SplitBar uses
35800 * @param {Object} adapter A SplitBar adapter object
35802 setAdapter : function(adapter){
35803 this.adapter = adapter;
35804 this.adapter.init(this);
35808 * Gets the minimum size for the resizing element
35809 * @return {Number} The minimum size
35811 getMinimumSize : function(){
35812 return this.minSize;
35816 * Sets the minimum size for the resizing element
35817 * @param {Number} minSize The minimum size
35819 setMinimumSize : function(minSize){
35820 this.minSize = minSize;
35824 * Gets the maximum size for the resizing element
35825 * @return {Number} The maximum size
35827 getMaximumSize : function(){
35828 return this.maxSize;
35832 * Sets the maximum size for the resizing element
35833 * @param {Number} maxSize The maximum size
35835 setMaximumSize : function(maxSize){
35836 this.maxSize = maxSize;
35840 * Sets the initialize size for the resizing element
35841 * @param {Number} size The initial size
35843 setCurrentSize : function(size){
35844 var oldAnimate = this.animate;
35845 this.animate = false;
35846 this.adapter.setElementSize(this, size);
35847 this.animate = oldAnimate;
35851 * Destroy this splitbar.
35852 * @param {Boolean} removeEl True to remove the element
35854 destroy : function(removeEl){
35856 this.shim.remove();
35859 this.proxy.parentNode.removeChild(this.proxy);
35867 * @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.
35869 Roo.bootstrap.SplitBar.createProxy = function(dir){
35870 var proxy = new Roo.Element(document.createElement("div"));
35871 proxy.unselectable();
35872 var cls = 'roo-splitbar-proxy';
35873 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
35874 document.body.appendChild(proxy.dom);
35879 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
35880 * Default Adapter. It assumes the splitter and resizing element are not positioned
35881 * elements and only gets/sets the width of the element. Generally used for table based layouts.
35883 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
35886 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
35887 // do nothing for now
35888 init : function(s){
35892 * Called before drag operations to get the current size of the resizing element.
35893 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
35895 getElementSize : function(s){
35896 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35897 return s.resizingEl.getWidth();
35899 return s.resizingEl.getHeight();
35904 * Called after drag operations to set the size of the resizing element.
35905 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
35906 * @param {Number} newSize The new size to set
35907 * @param {Function} onComplete A function to be invoked when resizing is complete
35909 setElementSize : function(s, newSize, onComplete){
35910 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35912 s.resizingEl.setWidth(newSize);
35914 onComplete(s, newSize);
35917 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
35922 s.resizingEl.setHeight(newSize);
35924 onComplete(s, newSize);
35927 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
35934 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
35935 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
35936 * Adapter that moves the splitter element to align with the resized sizing element.
35937 * Used with an absolute positioned SplitBar.
35938 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
35939 * document.body, make sure you assign an id to the body element.
35941 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
35942 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
35943 this.container = Roo.get(container);
35946 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
35947 init : function(s){
35948 this.basic.init(s);
35951 getElementSize : function(s){
35952 return this.basic.getElementSize(s);
35955 setElementSize : function(s, newSize, onComplete){
35956 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
35959 moveSplitter : function(s){
35960 var yes = Roo.bootstrap.SplitBar;
35961 switch(s.placement){
35963 s.el.setX(s.resizingEl.getRight());
35966 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
35969 s.el.setY(s.resizingEl.getBottom());
35972 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
35979 * Orientation constant - Create a vertical SplitBar
35983 Roo.bootstrap.SplitBar.VERTICAL = 1;
35986 * Orientation constant - Create a horizontal SplitBar
35990 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
35993 * Placement constant - The resizing element is to the left of the splitter element
35997 Roo.bootstrap.SplitBar.LEFT = 1;
36000 * Placement constant - The resizing element is to the right of the splitter element
36004 Roo.bootstrap.SplitBar.RIGHT = 2;
36007 * Placement constant - The resizing element is positioned above the splitter element
36011 Roo.bootstrap.SplitBar.TOP = 3;
36014 * Placement constant - The resizing element is positioned under splitter element
36018 Roo.bootstrap.SplitBar.BOTTOM = 4;
36019 Roo.namespace("Roo.bootstrap.layout");/*
36021 * Ext JS Library 1.1.1
36022 * Copyright(c) 2006-2007, Ext JS, LLC.
36024 * Originally Released Under LGPL - original licence link has changed is not relivant.
36027 * <script type="text/javascript">
36031 * @class Roo.bootstrap.layout.Manager
36032 * @extends Roo.bootstrap.Component
36033 * Base class for layout managers.
36035 Roo.bootstrap.layout.Manager = function(config)
36037 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
36043 /** false to disable window resize monitoring @type Boolean */
36044 this.monitorWindowResize = true;
36049 * Fires when a layout is performed.
36050 * @param {Roo.LayoutManager} this
36054 * @event regionresized
36055 * Fires when the user resizes a region.
36056 * @param {Roo.LayoutRegion} region The resized region
36057 * @param {Number} newSize The new size (width for east/west, height for north/south)
36059 "regionresized" : true,
36061 * @event regioncollapsed
36062 * Fires when a region is collapsed.
36063 * @param {Roo.LayoutRegion} region The collapsed region
36065 "regioncollapsed" : true,
36067 * @event regionexpanded
36068 * Fires when a region is expanded.
36069 * @param {Roo.LayoutRegion} region The expanded region
36071 "regionexpanded" : true
36073 this.updating = false;
36076 this.el = Roo.get(config.el);
36082 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
36087 monitorWindowResize : true,
36093 onRender : function(ct, position)
36096 this.el = Roo.get(ct);
36099 //this.fireEvent('render',this);
36103 initEvents: function()
36107 // ie scrollbar fix
36108 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
36109 document.body.scroll = "no";
36110 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
36111 this.el.position('relative');
36113 this.id = this.el.id;
36114 this.el.addClass("roo-layout-container");
36115 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
36116 if(this.el.dom != document.body ) {
36117 this.el.on('resize', this.layout,this);
36118 this.el.on('show', this.layout,this);
36124 * Returns true if this layout is currently being updated
36125 * @return {Boolean}
36127 isUpdating : function(){
36128 return this.updating;
36132 * Suspend the LayoutManager from doing auto-layouts while
36133 * making multiple add or remove calls
36135 beginUpdate : function(){
36136 this.updating = true;
36140 * Restore auto-layouts and optionally disable the manager from performing a layout
36141 * @param {Boolean} noLayout true to disable a layout update
36143 endUpdate : function(noLayout){
36144 this.updating = false;
36150 layout: function(){
36154 onRegionResized : function(region, newSize){
36155 this.fireEvent("regionresized", region, newSize);
36159 onRegionCollapsed : function(region){
36160 this.fireEvent("regioncollapsed", region);
36163 onRegionExpanded : function(region){
36164 this.fireEvent("regionexpanded", region);
36168 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
36169 * performs box-model adjustments.
36170 * @return {Object} The size as an object {width: (the width), height: (the height)}
36172 getViewSize : function()
36175 if(this.el.dom != document.body){
36176 size = this.el.getSize();
36178 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
36180 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
36181 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36186 * Returns the Element this layout is bound to.
36187 * @return {Roo.Element}
36189 getEl : function(){
36194 * Returns the specified region.
36195 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
36196 * @return {Roo.LayoutRegion}
36198 getRegion : function(target){
36199 return this.regions[target.toLowerCase()];
36202 onWindowResize : function(){
36203 if(this.monitorWindowResize){
36210 * Ext JS Library 1.1.1
36211 * Copyright(c) 2006-2007, Ext JS, LLC.
36213 * Originally Released Under LGPL - original licence link has changed is not relivant.
36216 * <script type="text/javascript">
36219 * @class Roo.bootstrap.layout.Border
36220 * @extends Roo.bootstrap.layout.Manager
36221 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
36222 * please see: examples/bootstrap/nested.html<br><br>
36224 <b>The container the layout is rendered into can be either the body element or any other element.
36225 If it is not the body element, the container needs to either be an absolute positioned element,
36226 or you will need to add "position:relative" to the css of the container. You will also need to specify
36227 the container size if it is not the body element.</b>
36230 * Create a new Border
36231 * @param {Object} config Configuration options
36233 Roo.bootstrap.layout.Border = function(config){
36234 config = config || {};
36235 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
36239 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
36240 if(config[region]){
36241 config[region].region = region;
36242 this.addRegion(config[region]);
36248 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
36250 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
36252 parent : false, // this might point to a 'nest' or a ???
36255 * Creates and adds a new region if it doesn't already exist.
36256 * @param {String} target The target region key (north, south, east, west or center).
36257 * @param {Object} config The regions config object
36258 * @return {BorderLayoutRegion} The new region
36260 addRegion : function(config)
36262 if(!this.regions[config.region]){
36263 var r = this.factory(config);
36264 this.bindRegion(r);
36266 return this.regions[config.region];
36270 bindRegion : function(r){
36271 this.regions[r.config.region] = r;
36273 r.on("visibilitychange", this.layout, this);
36274 r.on("paneladded", this.layout, this);
36275 r.on("panelremoved", this.layout, this);
36276 r.on("invalidated", this.layout, this);
36277 r.on("resized", this.onRegionResized, this);
36278 r.on("collapsed", this.onRegionCollapsed, this);
36279 r.on("expanded", this.onRegionExpanded, this);
36283 * Performs a layout update.
36285 layout : function()
36287 if(this.updating) {
36291 // render all the rebions if they have not been done alreayd?
36292 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
36293 if(this.regions[region] && !this.regions[region].bodyEl){
36294 this.regions[region].onRender(this.el)
36298 var size = this.getViewSize();
36299 var w = size.width;
36300 var h = size.height;
36305 //var x = 0, y = 0;
36307 var rs = this.regions;
36308 var north = rs["north"];
36309 var south = rs["south"];
36310 var west = rs["west"];
36311 var east = rs["east"];
36312 var center = rs["center"];
36313 //if(this.hideOnLayout){ // not supported anymore
36314 //c.el.setStyle("display", "none");
36316 if(north && north.isVisible()){
36317 var b = north.getBox();
36318 var m = north.getMargins();
36319 b.width = w - (m.left+m.right);
36322 centerY = b.height + b.y + m.bottom;
36323 centerH -= centerY;
36324 north.updateBox(this.safeBox(b));
36326 if(south && south.isVisible()){
36327 var b = south.getBox();
36328 var m = south.getMargins();
36329 b.width = w - (m.left+m.right);
36331 var totalHeight = (b.height + m.top + m.bottom);
36332 b.y = h - totalHeight + m.top;
36333 centerH -= totalHeight;
36334 south.updateBox(this.safeBox(b));
36336 if(west && west.isVisible()){
36337 var b = west.getBox();
36338 var m = west.getMargins();
36339 b.height = centerH - (m.top+m.bottom);
36341 b.y = centerY + m.top;
36342 var totalWidth = (b.width + m.left + m.right);
36343 centerX += totalWidth;
36344 centerW -= totalWidth;
36345 west.updateBox(this.safeBox(b));
36347 if(east && east.isVisible()){
36348 var b = east.getBox();
36349 var m = east.getMargins();
36350 b.height = centerH - (m.top+m.bottom);
36351 var totalWidth = (b.width + m.left + m.right);
36352 b.x = w - totalWidth + m.left;
36353 b.y = centerY + m.top;
36354 centerW -= totalWidth;
36355 east.updateBox(this.safeBox(b));
36358 var m = center.getMargins();
36360 x: centerX + m.left,
36361 y: centerY + m.top,
36362 width: centerW - (m.left+m.right),
36363 height: centerH - (m.top+m.bottom)
36365 //if(this.hideOnLayout){
36366 //center.el.setStyle("display", "block");
36368 center.updateBox(this.safeBox(centerBox));
36371 this.fireEvent("layout", this);
36375 safeBox : function(box){
36376 box.width = Math.max(0, box.width);
36377 box.height = Math.max(0, box.height);
36382 * Adds a ContentPanel (or subclass) to this layout.
36383 * @param {String} target The target region key (north, south, east, west or center).
36384 * @param {Roo.ContentPanel} panel The panel to add
36385 * @return {Roo.ContentPanel} The added panel
36387 add : function(target, panel){
36389 target = target.toLowerCase();
36390 return this.regions[target].add(panel);
36394 * Remove a ContentPanel (or subclass) to this layout.
36395 * @param {String} target The target region key (north, south, east, west or center).
36396 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
36397 * @return {Roo.ContentPanel} The removed panel
36399 remove : function(target, panel){
36400 target = target.toLowerCase();
36401 return this.regions[target].remove(panel);
36405 * Searches all regions for a panel with the specified id
36406 * @param {String} panelId
36407 * @return {Roo.ContentPanel} The panel or null if it wasn't found
36409 findPanel : function(panelId){
36410 var rs = this.regions;
36411 for(var target in rs){
36412 if(typeof rs[target] != "function"){
36413 var p = rs[target].getPanel(panelId);
36423 * Searches all regions for a panel with the specified id and activates (shows) it.
36424 * @param {String/ContentPanel} panelId The panels id or the panel itself
36425 * @return {Roo.ContentPanel} The shown panel or null
36427 showPanel : function(panelId) {
36428 var rs = this.regions;
36429 for(var target in rs){
36430 var r = rs[target];
36431 if(typeof r != "function"){
36432 if(r.hasPanel(panelId)){
36433 return r.showPanel(panelId);
36441 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
36442 * @param {Roo.state.Provider} provider (optional) An alternate state provider
36445 restoreState : function(provider){
36447 provider = Roo.state.Manager;
36449 var sm = new Roo.LayoutStateManager();
36450 sm.init(this, provider);
36456 * Adds a xtype elements to the layout.
36460 xtype : 'ContentPanel',
36467 xtype : 'NestedLayoutPanel',
36473 items : [ ... list of content panels or nested layout panels.. ]
36477 * @param {Object} cfg Xtype definition of item to add.
36479 addxtype : function(cfg)
36481 // basically accepts a pannel...
36482 // can accept a layout region..!?!?
36483 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
36486 // theory? children can only be panels??
36488 //if (!cfg.xtype.match(/Panel$/)) {
36493 if (typeof(cfg.region) == 'undefined') {
36494 Roo.log("Failed to add Panel, region was not set");
36498 var region = cfg.region;
36504 xitems = cfg.items;
36509 if ( region == 'center') {
36510 Roo.log("Center: " + cfg.title);
36516 case 'Content': // ContentPanel (el, cfg)
36517 case 'Scroll': // ContentPanel (el, cfg)
36519 cfg.autoCreate = cfg.autoCreate || true;
36520 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36522 // var el = this.el.createChild();
36523 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
36526 this.add(region, ret);
36530 case 'TreePanel': // our new panel!
36531 cfg.el = this.el.createChild();
36532 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
36533 this.add(region, ret);
36538 // create a new Layout (which is a Border Layout...
36540 var clayout = cfg.layout;
36541 clayout.el = this.el.createChild();
36542 clayout.items = clayout.items || [];
36546 // replace this exitems with the clayout ones..
36547 xitems = clayout.items;
36549 // force background off if it's in center...
36550 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
36551 cfg.background = false;
36553 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
36556 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36557 //console.log('adding nested layout panel ' + cfg.toSource());
36558 this.add(region, ret);
36559 nb = {}; /// find first...
36564 // needs grid and region
36566 //var el = this.getRegion(region).el.createChild();
36568 *var el = this.el.createChild();
36569 // create the grid first...
36570 cfg.grid.container = el;
36571 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
36574 if (region == 'center' && this.active ) {
36575 cfg.background = false;
36578 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36580 this.add(region, ret);
36582 if (cfg.background) {
36583 // render grid on panel activation (if panel background)
36584 ret.on('activate', function(gp) {
36585 if (!gp.grid.rendered) {
36586 // gp.grid.render(el);
36590 // cfg.grid.render(el);
36596 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
36597 // it was the old xcomponent building that caused this before.
36598 // espeically if border is the top element in the tree.
36608 if (typeof(Roo[cfg.xtype]) != 'undefined') {
36610 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
36611 this.add(region, ret);
36615 throw "Can not add '" + cfg.xtype + "' to Border";
36621 this.beginUpdate();
36625 Roo.each(xitems, function(i) {
36626 region = nb && i.region ? i.region : false;
36628 var add = ret.addxtype(i);
36631 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
36632 if (!i.background) {
36633 abn[region] = nb[region] ;
36640 // make the last non-background panel active..
36641 //if (nb) { Roo.log(abn); }
36644 for(var r in abn) {
36645 region = this.getRegion(r);
36647 // tried using nb[r], but it does not work..
36649 region.showPanel(abn[r]);
36660 factory : function(cfg)
36663 var validRegions = Roo.bootstrap.layout.Border.regions;
36665 var target = cfg.region;
36668 var r = Roo.bootstrap.layout;
36672 return new r.North(cfg);
36674 return new r.South(cfg);
36676 return new r.East(cfg);
36678 return new r.West(cfg);
36680 return new r.Center(cfg);
36682 throw 'Layout region "'+target+'" not supported.';
36689 * Ext JS Library 1.1.1
36690 * Copyright(c) 2006-2007, Ext JS, LLC.
36692 * Originally Released Under LGPL - original licence link has changed is not relivant.
36695 * <script type="text/javascript">
36699 * @class Roo.bootstrap.layout.Basic
36700 * @extends Roo.util.Observable
36701 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
36702 * and does not have a titlebar, tabs or any other features. All it does is size and position
36703 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
36704 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36705 * @cfg {string} region the region that it inhabits..
36706 * @cfg {bool} skipConfig skip config?
36710 Roo.bootstrap.layout.Basic = function(config){
36712 this.mgr = config.mgr;
36714 this.position = config.region;
36716 var skipConfig = config.skipConfig;
36720 * @scope Roo.BasicLayoutRegion
36724 * @event beforeremove
36725 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
36726 * @param {Roo.LayoutRegion} this
36727 * @param {Roo.ContentPanel} panel The panel
36728 * @param {Object} e The cancel event object
36730 "beforeremove" : true,
36732 * @event invalidated
36733 * Fires when the layout for this region is changed.
36734 * @param {Roo.LayoutRegion} this
36736 "invalidated" : true,
36738 * @event visibilitychange
36739 * Fires when this region is shown or hidden
36740 * @param {Roo.LayoutRegion} this
36741 * @param {Boolean} visibility true or false
36743 "visibilitychange" : true,
36745 * @event paneladded
36746 * Fires when a panel is added.
36747 * @param {Roo.LayoutRegion} this
36748 * @param {Roo.ContentPanel} panel The panel
36750 "paneladded" : true,
36752 * @event panelremoved
36753 * Fires when a panel is removed.
36754 * @param {Roo.LayoutRegion} this
36755 * @param {Roo.ContentPanel} panel The panel
36757 "panelremoved" : true,
36759 * @event beforecollapse
36760 * Fires when this region before collapse.
36761 * @param {Roo.LayoutRegion} this
36763 "beforecollapse" : true,
36766 * Fires when this region is collapsed.
36767 * @param {Roo.LayoutRegion} this
36769 "collapsed" : true,
36772 * Fires when this region is expanded.
36773 * @param {Roo.LayoutRegion} this
36778 * Fires when this region is slid into view.
36779 * @param {Roo.LayoutRegion} this
36781 "slideshow" : true,
36784 * Fires when this region slides out of view.
36785 * @param {Roo.LayoutRegion} this
36787 "slidehide" : true,
36789 * @event panelactivated
36790 * Fires when a panel is activated.
36791 * @param {Roo.LayoutRegion} this
36792 * @param {Roo.ContentPanel} panel The activated panel
36794 "panelactivated" : true,
36797 * Fires when the user resizes this region.
36798 * @param {Roo.LayoutRegion} this
36799 * @param {Number} newSize The new size (width for east/west, height for north/south)
36803 /** A collection of panels in this region. @type Roo.util.MixedCollection */
36804 this.panels = new Roo.util.MixedCollection();
36805 this.panels.getKey = this.getPanelId.createDelegate(this);
36807 this.activePanel = null;
36808 // ensure listeners are added...
36810 if (config.listeners || config.events) {
36811 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
36812 listeners : config.listeners || {},
36813 events : config.events || {}
36817 if(skipConfig !== true){
36818 this.applyConfig(config);
36822 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
36824 getPanelId : function(p){
36828 applyConfig : function(config){
36829 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36830 this.config = config;
36835 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
36836 * the width, for horizontal (north, south) the height.
36837 * @param {Number} newSize The new width or height
36839 resizeTo : function(newSize){
36840 var el = this.el ? this.el :
36841 (this.activePanel ? this.activePanel.getEl() : null);
36843 switch(this.position){
36846 el.setWidth(newSize);
36847 this.fireEvent("resized", this, newSize);
36851 el.setHeight(newSize);
36852 this.fireEvent("resized", this, newSize);
36858 getBox : function(){
36859 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
36862 getMargins : function(){
36863 return this.margins;
36866 updateBox : function(box){
36868 var el = this.activePanel.getEl();
36869 el.dom.style.left = box.x + "px";
36870 el.dom.style.top = box.y + "px";
36871 this.activePanel.setSize(box.width, box.height);
36875 * Returns the container element for this region.
36876 * @return {Roo.Element}
36878 getEl : function(){
36879 return this.activePanel;
36883 * Returns true if this region is currently visible.
36884 * @return {Boolean}
36886 isVisible : function(){
36887 return this.activePanel ? true : false;
36890 setActivePanel : function(panel){
36891 panel = this.getPanel(panel);
36892 if(this.activePanel && this.activePanel != panel){
36893 this.activePanel.setActiveState(false);
36894 this.activePanel.getEl().setLeftTop(-10000,-10000);
36896 this.activePanel = panel;
36897 panel.setActiveState(true);
36899 panel.setSize(this.box.width, this.box.height);
36901 this.fireEvent("panelactivated", this, panel);
36902 this.fireEvent("invalidated");
36906 * Show the specified panel.
36907 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
36908 * @return {Roo.ContentPanel} The shown panel or null
36910 showPanel : function(panel){
36911 panel = this.getPanel(panel);
36913 this.setActivePanel(panel);
36919 * Get the active panel for this region.
36920 * @return {Roo.ContentPanel} The active panel or null
36922 getActivePanel : function(){
36923 return this.activePanel;
36927 * Add the passed ContentPanel(s)
36928 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36929 * @return {Roo.ContentPanel} The panel added (if only one was added)
36931 add : function(panel){
36932 if(arguments.length > 1){
36933 for(var i = 0, len = arguments.length; i < len; i++) {
36934 this.add(arguments[i]);
36938 if(this.hasPanel(panel)){
36939 this.showPanel(panel);
36942 var el = panel.getEl();
36943 if(el.dom.parentNode != this.mgr.el.dom){
36944 this.mgr.el.dom.appendChild(el.dom);
36946 if(panel.setRegion){
36947 panel.setRegion(this);
36949 this.panels.add(panel);
36950 el.setStyle("position", "absolute");
36951 if(!panel.background){
36952 this.setActivePanel(panel);
36953 if(this.config.initialSize && this.panels.getCount()==1){
36954 this.resizeTo(this.config.initialSize);
36957 this.fireEvent("paneladded", this, panel);
36962 * Returns true if the panel is in this region.
36963 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36964 * @return {Boolean}
36966 hasPanel : function(panel){
36967 if(typeof panel == "object"){ // must be panel obj
36968 panel = panel.getId();
36970 return this.getPanel(panel) ? true : false;
36974 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36975 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36976 * @param {Boolean} preservePanel Overrides the config preservePanel option
36977 * @return {Roo.ContentPanel} The panel that was removed
36979 remove : function(panel, preservePanel){
36980 panel = this.getPanel(panel);
36985 this.fireEvent("beforeremove", this, panel, e);
36986 if(e.cancel === true){
36989 var panelId = panel.getId();
36990 this.panels.removeKey(panelId);
36995 * Returns the panel specified or null if it's not in this region.
36996 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36997 * @return {Roo.ContentPanel}
36999 getPanel : function(id){
37000 if(typeof id == "object"){ // must be panel obj
37003 return this.panels.get(id);
37007 * Returns this regions position (north/south/east/west/center).
37010 getPosition: function(){
37011 return this.position;
37015 * Ext JS Library 1.1.1
37016 * Copyright(c) 2006-2007, Ext JS, LLC.
37018 * Originally Released Under LGPL - original licence link has changed is not relivant.
37021 * <script type="text/javascript">
37025 * @class Roo.bootstrap.layout.Region
37026 * @extends Roo.bootstrap.layout.Basic
37027 * This class represents a region in a layout manager.
37029 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
37030 * @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})
37031 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
37032 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
37033 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
37034 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
37035 * @cfg {String} title The title for the region (overrides panel titles)
37036 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
37037 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
37038 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
37039 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
37040 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
37041 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
37042 * the space available, similar to FireFox 1.5 tabs (defaults to false)
37043 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
37044 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
37045 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
37047 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
37048 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
37049 * @cfg {Boolean} disableTabTips True to disable tab tooltips
37050 * @cfg {Number} width For East/West panels
37051 * @cfg {Number} height For North/South panels
37052 * @cfg {Boolean} split To show the splitter
37053 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
37055 * @cfg {string} cls Extra CSS classes to add to region
37057 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37058 * @cfg {string} region the region that it inhabits..
37061 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
37062 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
37064 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
37065 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
37066 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
37068 Roo.bootstrap.layout.Region = function(config)
37070 this.applyConfig(config);
37072 var mgr = config.mgr;
37073 var pos = config.region;
37074 config.skipConfig = true;
37075 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
37078 this.onRender(mgr.el);
37081 this.visible = true;
37082 this.collapsed = false;
37083 this.unrendered_panels = [];
37086 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
37088 position: '', // set by wrapper (eg. north/south etc..)
37089 unrendered_panels : null, // unrendered panels.
37091 tabPosition : false,
37093 mgr: false, // points to 'Border'
37096 createBody : function(){
37097 /** This region's body element
37098 * @type Roo.Element */
37099 this.bodyEl = this.el.createChild({
37101 cls: "roo-layout-panel-body tab-content" // bootstrap added...
37105 onRender: function(ctr, pos)
37107 var dh = Roo.DomHelper;
37108 /** This region's container element
37109 * @type Roo.Element */
37110 this.el = dh.append(ctr.dom, {
37112 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
37114 /** This region's title element
37115 * @type Roo.Element */
37117 this.titleEl = dh.append(this.el.dom, {
37119 unselectable: "on",
37120 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
37122 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
37123 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
37127 this.titleEl.enableDisplayMode();
37128 /** This region's title text element
37129 * @type HTMLElement */
37130 this.titleTextEl = this.titleEl.dom.firstChild;
37131 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
37133 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
37134 this.closeBtn.enableDisplayMode();
37135 this.closeBtn.on("click", this.closeClicked, this);
37136 this.closeBtn.hide();
37138 this.createBody(this.config);
37139 if(this.config.hideWhenEmpty){
37141 this.on("paneladded", this.validateVisibility, this);
37142 this.on("panelremoved", this.validateVisibility, this);
37144 if(this.autoScroll){
37145 this.bodyEl.setStyle("overflow", "auto");
37147 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
37149 //if(c.titlebar !== false){
37150 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
37151 this.titleEl.hide();
37153 this.titleEl.show();
37154 if(this.config.title){
37155 this.titleTextEl.innerHTML = this.config.title;
37159 if(this.config.collapsed){
37160 this.collapse(true);
37162 if(this.config.hidden){
37166 if (this.unrendered_panels && this.unrendered_panels.length) {
37167 for (var i =0;i< this.unrendered_panels.length; i++) {
37168 this.add(this.unrendered_panels[i]);
37170 this.unrendered_panels = null;
37176 applyConfig : function(c)
37179 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
37180 var dh = Roo.DomHelper;
37181 if(c.titlebar !== false){
37182 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
37183 this.collapseBtn.on("click", this.collapse, this);
37184 this.collapseBtn.enableDisplayMode();
37186 if(c.showPin === true || this.showPin){
37187 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
37188 this.stickBtn.enableDisplayMode();
37189 this.stickBtn.on("click", this.expand, this);
37190 this.stickBtn.hide();
37195 /** This region's collapsed element
37196 * @type Roo.Element */
37199 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
37200 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
37203 if(c.floatable !== false){
37204 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
37205 this.collapsedEl.on("click", this.collapseClick, this);
37208 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
37209 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
37210 id: "message", unselectable: "on", style:{"float":"left"}});
37211 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
37213 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
37214 this.expandBtn.on("click", this.expand, this);
37218 if(this.collapseBtn){
37219 this.collapseBtn.setVisible(c.collapsible == true);
37222 this.cmargins = c.cmargins || this.cmargins ||
37223 (this.position == "west" || this.position == "east" ?
37224 {top: 0, left: 2, right:2, bottom: 0} :
37225 {top: 2, left: 0, right:0, bottom: 2});
37227 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
37230 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
37232 this.autoScroll = c.autoScroll || false;
37237 this.duration = c.duration || .30;
37238 this.slideDuration = c.slideDuration || .45;
37243 * Returns true if this region is currently visible.
37244 * @return {Boolean}
37246 isVisible : function(){
37247 return this.visible;
37251 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
37252 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
37254 //setCollapsedTitle : function(title){
37255 // title = title || " ";
37256 // if(this.collapsedTitleTextEl){
37257 // this.collapsedTitleTextEl.innerHTML = title;
37261 getBox : function(){
37263 // if(!this.collapsed){
37264 b = this.el.getBox(false, true);
37266 // b = this.collapsedEl.getBox(false, true);
37271 getMargins : function(){
37272 return this.margins;
37273 //return this.collapsed ? this.cmargins : this.margins;
37276 highlight : function(){
37277 this.el.addClass("x-layout-panel-dragover");
37280 unhighlight : function(){
37281 this.el.removeClass("x-layout-panel-dragover");
37284 updateBox : function(box)
37286 if (!this.bodyEl) {
37287 return; // not rendered yet..
37291 if(!this.collapsed){
37292 this.el.dom.style.left = box.x + "px";
37293 this.el.dom.style.top = box.y + "px";
37294 this.updateBody(box.width, box.height);
37296 this.collapsedEl.dom.style.left = box.x + "px";
37297 this.collapsedEl.dom.style.top = box.y + "px";
37298 this.collapsedEl.setSize(box.width, box.height);
37301 this.tabs.autoSizeTabs();
37305 updateBody : function(w, h)
37308 this.el.setWidth(w);
37309 w -= this.el.getBorderWidth("rl");
37310 if(this.config.adjustments){
37311 w += this.config.adjustments[0];
37314 if(h !== null && h > 0){
37315 this.el.setHeight(h);
37316 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
37317 h -= this.el.getBorderWidth("tb");
37318 if(this.config.adjustments){
37319 h += this.config.adjustments[1];
37321 this.bodyEl.setHeight(h);
37323 h = this.tabs.syncHeight(h);
37326 if(this.panelSize){
37327 w = w !== null ? w : this.panelSize.width;
37328 h = h !== null ? h : this.panelSize.height;
37330 if(this.activePanel){
37331 var el = this.activePanel.getEl();
37332 w = w !== null ? w : el.getWidth();
37333 h = h !== null ? h : el.getHeight();
37334 this.panelSize = {width: w, height: h};
37335 this.activePanel.setSize(w, h);
37337 if(Roo.isIE && this.tabs){
37338 this.tabs.el.repaint();
37343 * Returns the container element for this region.
37344 * @return {Roo.Element}
37346 getEl : function(){
37351 * Hides this region.
37354 //if(!this.collapsed){
37355 this.el.dom.style.left = "-2000px";
37358 // this.collapsedEl.dom.style.left = "-2000px";
37359 // this.collapsedEl.hide();
37361 this.visible = false;
37362 this.fireEvent("visibilitychange", this, false);
37366 * Shows this region if it was previously hidden.
37369 //if(!this.collapsed){
37372 // this.collapsedEl.show();
37374 this.visible = true;
37375 this.fireEvent("visibilitychange", this, true);
37378 closeClicked : function(){
37379 if(this.activePanel){
37380 this.remove(this.activePanel);
37384 collapseClick : function(e){
37386 e.stopPropagation();
37389 e.stopPropagation();
37395 * Collapses this region.
37396 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
37399 collapse : function(skipAnim, skipCheck = false){
37400 if(this.collapsed) {
37404 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
37406 this.collapsed = true;
37408 this.split.el.hide();
37410 if(this.config.animate && skipAnim !== true){
37411 this.fireEvent("invalidated", this);
37412 this.animateCollapse();
37414 this.el.setLocation(-20000,-20000);
37416 this.collapsedEl.show();
37417 this.fireEvent("collapsed", this);
37418 this.fireEvent("invalidated", this);
37424 animateCollapse : function(){
37429 * Expands this region if it was previously collapsed.
37430 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
37431 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
37434 expand : function(e, skipAnim){
37436 e.stopPropagation();
37438 if(!this.collapsed || this.el.hasActiveFx()) {
37442 this.afterSlideIn();
37445 this.collapsed = false;
37446 if(this.config.animate && skipAnim !== true){
37447 this.animateExpand();
37451 this.split.el.show();
37453 this.collapsedEl.setLocation(-2000,-2000);
37454 this.collapsedEl.hide();
37455 this.fireEvent("invalidated", this);
37456 this.fireEvent("expanded", this);
37460 animateExpand : function(){
37464 initTabs : function()
37466 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
37468 var ts = new Roo.bootstrap.panel.Tabs({
37469 el: this.bodyEl.dom,
37471 tabPosition: this.tabPosition ? this.tabPosition : 'top',
37472 disableTooltips: this.config.disableTabTips,
37473 toolbar : this.config.toolbar
37476 if(this.config.hideTabs){
37477 ts.stripWrap.setDisplayed(false);
37480 ts.resizeTabs = this.config.resizeTabs === true;
37481 ts.minTabWidth = this.config.minTabWidth || 40;
37482 ts.maxTabWidth = this.config.maxTabWidth || 250;
37483 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
37484 ts.monitorResize = false;
37485 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
37486 ts.bodyEl.addClass('roo-layout-tabs-body');
37487 this.panels.each(this.initPanelAsTab, this);
37490 initPanelAsTab : function(panel){
37491 var ti = this.tabs.addTab(
37495 this.config.closeOnTab && panel.isClosable(),
37498 if(panel.tabTip !== undefined){
37499 ti.setTooltip(panel.tabTip);
37501 ti.on("activate", function(){
37502 this.setActivePanel(panel);
37505 if(this.config.closeOnTab){
37506 ti.on("beforeclose", function(t, e){
37508 this.remove(panel);
37512 panel.tabItem = ti;
37517 updatePanelTitle : function(panel, title)
37519 if(this.activePanel == panel){
37520 this.updateTitle(title);
37523 var ti = this.tabs.getTab(panel.getEl().id);
37525 if(panel.tabTip !== undefined){
37526 ti.setTooltip(panel.tabTip);
37531 updateTitle : function(title){
37532 if(this.titleTextEl && !this.config.title){
37533 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
37537 setActivePanel : function(panel)
37539 panel = this.getPanel(panel);
37540 if(this.activePanel && this.activePanel != panel){
37541 if(this.activePanel.setActiveState(false) === false){
37545 this.activePanel = panel;
37546 panel.setActiveState(true);
37547 if(this.panelSize){
37548 panel.setSize(this.panelSize.width, this.panelSize.height);
37551 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
37553 this.updateTitle(panel.getTitle());
37555 this.fireEvent("invalidated", this);
37557 this.fireEvent("panelactivated", this, panel);
37561 * Shows the specified panel.
37562 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
37563 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
37565 showPanel : function(panel)
37567 panel = this.getPanel(panel);
37570 var tab = this.tabs.getTab(panel.getEl().id);
37571 if(tab.isHidden()){
37572 this.tabs.unhideTab(tab.id);
37576 this.setActivePanel(panel);
37583 * Get the active panel for this region.
37584 * @return {Roo.ContentPanel} The active panel or null
37586 getActivePanel : function(){
37587 return this.activePanel;
37590 validateVisibility : function(){
37591 if(this.panels.getCount() < 1){
37592 this.updateTitle(" ");
37593 this.closeBtn.hide();
37596 if(!this.isVisible()){
37603 * Adds the passed ContentPanel(s) to this region.
37604 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
37605 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
37607 add : function(panel)
37609 if(arguments.length > 1){
37610 for(var i = 0, len = arguments.length; i < len; i++) {
37611 this.add(arguments[i]);
37616 // if we have not been rendered yet, then we can not really do much of this..
37617 if (!this.bodyEl) {
37618 this.unrendered_panels.push(panel);
37625 if(this.hasPanel(panel)){
37626 this.showPanel(panel);
37629 panel.setRegion(this);
37630 this.panels.add(panel);
37631 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
37632 // sinle panel - no tab...?? would it not be better to render it with the tabs,
37633 // and hide them... ???
37634 this.bodyEl.dom.appendChild(panel.getEl().dom);
37635 if(panel.background !== true){
37636 this.setActivePanel(panel);
37638 this.fireEvent("paneladded", this, panel);
37645 this.initPanelAsTab(panel);
37649 if(panel.background !== true){
37650 this.tabs.activate(panel.getEl().id);
37652 this.fireEvent("paneladded", this, panel);
37657 * Hides the tab for the specified panel.
37658 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37660 hidePanel : function(panel){
37661 if(this.tabs && (panel = this.getPanel(panel))){
37662 this.tabs.hideTab(panel.getEl().id);
37667 * Unhides the tab for a previously hidden panel.
37668 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37670 unhidePanel : function(panel){
37671 if(this.tabs && (panel = this.getPanel(panel))){
37672 this.tabs.unhideTab(panel.getEl().id);
37676 clearPanels : function(){
37677 while(this.panels.getCount() > 0){
37678 this.remove(this.panels.first());
37683 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
37684 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37685 * @param {Boolean} preservePanel Overrides the config preservePanel option
37686 * @return {Roo.ContentPanel} The panel that was removed
37688 remove : function(panel, preservePanel)
37690 panel = this.getPanel(panel);
37695 this.fireEvent("beforeremove", this, panel, e);
37696 if(e.cancel === true){
37699 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
37700 var panelId = panel.getId();
37701 this.panels.removeKey(panelId);
37703 document.body.appendChild(panel.getEl().dom);
37706 this.tabs.removeTab(panel.getEl().id);
37707 }else if (!preservePanel){
37708 this.bodyEl.dom.removeChild(panel.getEl().dom);
37710 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
37711 var p = this.panels.first();
37712 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
37713 tempEl.appendChild(p.getEl().dom);
37714 this.bodyEl.update("");
37715 this.bodyEl.dom.appendChild(p.getEl().dom);
37717 this.updateTitle(p.getTitle());
37719 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
37720 this.setActivePanel(p);
37722 panel.setRegion(null);
37723 if(this.activePanel == panel){
37724 this.activePanel = null;
37726 if(this.config.autoDestroy !== false && preservePanel !== true){
37727 try{panel.destroy();}catch(e){}
37729 this.fireEvent("panelremoved", this, panel);
37734 * Returns the TabPanel component used by this region
37735 * @return {Roo.TabPanel}
37737 getTabs : function(){
37741 createTool : function(parentEl, className){
37742 var btn = Roo.DomHelper.append(parentEl, {
37744 cls: "x-layout-tools-button",
37747 cls: "roo-layout-tools-button-inner " + className,
37751 btn.addClassOnOver("roo-layout-tools-button-over");
37756 * Ext JS Library 1.1.1
37757 * Copyright(c) 2006-2007, Ext JS, LLC.
37759 * Originally Released Under LGPL - original licence link has changed is not relivant.
37762 * <script type="text/javascript">
37768 * @class Roo.SplitLayoutRegion
37769 * @extends Roo.LayoutRegion
37770 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
37772 Roo.bootstrap.layout.Split = function(config){
37773 this.cursor = config.cursor;
37774 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
37777 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
37779 splitTip : "Drag to resize.",
37780 collapsibleSplitTip : "Drag to resize. Double click to hide.",
37781 useSplitTips : false,
37783 applyConfig : function(config){
37784 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
37787 onRender : function(ctr,pos) {
37789 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
37790 if(!this.config.split){
37795 var splitEl = Roo.DomHelper.append(ctr.dom, {
37797 id: this.el.id + "-split",
37798 cls: "roo-layout-split roo-layout-split-"+this.position,
37801 /** The SplitBar for this region
37802 * @type Roo.SplitBar */
37803 // does not exist yet...
37804 Roo.log([this.position, this.orientation]);
37806 this.split = new Roo.bootstrap.SplitBar({
37807 dragElement : splitEl,
37808 resizingElement: this.el,
37809 orientation : this.orientation
37812 this.split.on("moved", this.onSplitMove, this);
37813 this.split.useShim = this.config.useShim === true;
37814 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
37815 if(this.useSplitTips){
37816 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
37818 //if(config.collapsible){
37819 // this.split.el.on("dblclick", this.collapse, this);
37822 if(typeof this.config.minSize != "undefined"){
37823 this.split.minSize = this.config.minSize;
37825 if(typeof this.config.maxSize != "undefined"){
37826 this.split.maxSize = this.config.maxSize;
37828 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
37829 this.hideSplitter();
37834 getHMaxSize : function(){
37835 var cmax = this.config.maxSize || 10000;
37836 var center = this.mgr.getRegion("center");
37837 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
37840 getVMaxSize : function(){
37841 var cmax = this.config.maxSize || 10000;
37842 var center = this.mgr.getRegion("center");
37843 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
37846 onSplitMove : function(split, newSize){
37847 this.fireEvent("resized", this, newSize);
37851 * Returns the {@link Roo.SplitBar} for this region.
37852 * @return {Roo.SplitBar}
37854 getSplitBar : function(){
37859 this.hideSplitter();
37860 Roo.bootstrap.layout.Split.superclass.hide.call(this);
37863 hideSplitter : function(){
37865 this.split.el.setLocation(-2000,-2000);
37866 this.split.el.hide();
37872 this.split.el.show();
37874 Roo.bootstrap.layout.Split.superclass.show.call(this);
37877 beforeSlide: function(){
37878 if(Roo.isGecko){// firefox overflow auto bug workaround
37879 this.bodyEl.clip();
37881 this.tabs.bodyEl.clip();
37883 if(this.activePanel){
37884 this.activePanel.getEl().clip();
37886 if(this.activePanel.beforeSlide){
37887 this.activePanel.beforeSlide();
37893 afterSlide : function(){
37894 if(Roo.isGecko){// firefox overflow auto bug workaround
37895 this.bodyEl.unclip();
37897 this.tabs.bodyEl.unclip();
37899 if(this.activePanel){
37900 this.activePanel.getEl().unclip();
37901 if(this.activePanel.afterSlide){
37902 this.activePanel.afterSlide();
37908 initAutoHide : function(){
37909 if(this.autoHide !== false){
37910 if(!this.autoHideHd){
37911 var st = new Roo.util.DelayedTask(this.slideIn, this);
37912 this.autoHideHd = {
37913 "mouseout": function(e){
37914 if(!e.within(this.el, true)){
37918 "mouseover" : function(e){
37924 this.el.on(this.autoHideHd);
37928 clearAutoHide : function(){
37929 if(this.autoHide !== false){
37930 this.el.un("mouseout", this.autoHideHd.mouseout);
37931 this.el.un("mouseover", this.autoHideHd.mouseover);
37935 clearMonitor : function(){
37936 Roo.get(document).un("click", this.slideInIf, this);
37939 // these names are backwards but not changed for compat
37940 slideOut : function(){
37941 if(this.isSlid || this.el.hasActiveFx()){
37944 this.isSlid = true;
37945 if(this.collapseBtn){
37946 this.collapseBtn.hide();
37948 this.closeBtnState = this.closeBtn.getStyle('display');
37949 this.closeBtn.hide();
37951 this.stickBtn.show();
37954 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
37955 this.beforeSlide();
37956 this.el.setStyle("z-index", 10001);
37957 this.el.slideIn(this.getSlideAnchor(), {
37958 callback: function(){
37960 this.initAutoHide();
37961 Roo.get(document).on("click", this.slideInIf, this);
37962 this.fireEvent("slideshow", this);
37969 afterSlideIn : function(){
37970 this.clearAutoHide();
37971 this.isSlid = false;
37972 this.clearMonitor();
37973 this.el.setStyle("z-index", "");
37974 if(this.collapseBtn){
37975 this.collapseBtn.show();
37977 this.closeBtn.setStyle('display', this.closeBtnState);
37979 this.stickBtn.hide();
37981 this.fireEvent("slidehide", this);
37984 slideIn : function(cb){
37985 if(!this.isSlid || this.el.hasActiveFx()){
37989 this.isSlid = false;
37990 this.beforeSlide();
37991 this.el.slideOut(this.getSlideAnchor(), {
37992 callback: function(){
37993 this.el.setLeftTop(-10000, -10000);
37995 this.afterSlideIn();
38003 slideInIf : function(e){
38004 if(!e.within(this.el)){
38009 animateCollapse : function(){
38010 this.beforeSlide();
38011 this.el.setStyle("z-index", 20000);
38012 var anchor = this.getSlideAnchor();
38013 this.el.slideOut(anchor, {
38014 callback : function(){
38015 this.el.setStyle("z-index", "");
38016 this.collapsedEl.slideIn(anchor, {duration:.3});
38018 this.el.setLocation(-10000,-10000);
38020 this.fireEvent("collapsed", this);
38027 animateExpand : function(){
38028 this.beforeSlide();
38029 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
38030 this.el.setStyle("z-index", 20000);
38031 this.collapsedEl.hide({
38034 this.el.slideIn(this.getSlideAnchor(), {
38035 callback : function(){
38036 this.el.setStyle("z-index", "");
38039 this.split.el.show();
38041 this.fireEvent("invalidated", this);
38042 this.fireEvent("expanded", this);
38070 getAnchor : function(){
38071 return this.anchors[this.position];
38074 getCollapseAnchor : function(){
38075 return this.canchors[this.position];
38078 getSlideAnchor : function(){
38079 return this.sanchors[this.position];
38082 getAlignAdj : function(){
38083 var cm = this.cmargins;
38084 switch(this.position){
38100 getExpandAdj : function(){
38101 var c = this.collapsedEl, cm = this.cmargins;
38102 switch(this.position){
38104 return [-(cm.right+c.getWidth()+cm.left), 0];
38107 return [cm.right+c.getWidth()+cm.left, 0];
38110 return [0, -(cm.top+cm.bottom+c.getHeight())];
38113 return [0, cm.top+cm.bottom+c.getHeight()];
38119 * Ext JS Library 1.1.1
38120 * Copyright(c) 2006-2007, Ext JS, LLC.
38122 * Originally Released Under LGPL - original licence link has changed is not relivant.
38125 * <script type="text/javascript">
38128 * These classes are private internal classes
38130 Roo.bootstrap.layout.Center = function(config){
38131 config.region = "center";
38132 Roo.bootstrap.layout.Region.call(this, config);
38133 this.visible = true;
38134 this.minWidth = config.minWidth || 20;
38135 this.minHeight = config.minHeight || 20;
38138 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
38140 // center panel can't be hidden
38144 // center panel can't be hidden
38147 getMinWidth: function(){
38148 return this.minWidth;
38151 getMinHeight: function(){
38152 return this.minHeight;
38166 Roo.bootstrap.layout.North = function(config)
38168 config.region = 'north';
38169 config.cursor = 'n-resize';
38171 Roo.bootstrap.layout.Split.call(this, config);
38175 this.split.placement = Roo.bootstrap.SplitBar.TOP;
38176 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38177 this.split.el.addClass("roo-layout-split-v");
38179 var size = config.initialSize || config.height;
38180 if(typeof size != "undefined"){
38181 this.el.setHeight(size);
38184 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
38186 orientation: Roo.bootstrap.SplitBar.VERTICAL,
38190 getBox : function(){
38191 if(this.collapsed){
38192 return this.collapsedEl.getBox();
38194 var box = this.el.getBox();
38196 box.height += this.split.el.getHeight();
38201 updateBox : function(box){
38202 if(this.split && !this.collapsed){
38203 box.height -= this.split.el.getHeight();
38204 this.split.el.setLeft(box.x);
38205 this.split.el.setTop(box.y+box.height);
38206 this.split.el.setWidth(box.width);
38208 if(this.collapsed){
38209 this.updateBody(box.width, null);
38211 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38219 Roo.bootstrap.layout.South = function(config){
38220 config.region = 'south';
38221 config.cursor = 's-resize';
38222 Roo.bootstrap.layout.Split.call(this, config);
38224 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
38225 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38226 this.split.el.addClass("roo-layout-split-v");
38228 var size = config.initialSize || config.height;
38229 if(typeof size != "undefined"){
38230 this.el.setHeight(size);
38234 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
38235 orientation: Roo.bootstrap.SplitBar.VERTICAL,
38236 getBox : function(){
38237 if(this.collapsed){
38238 return this.collapsedEl.getBox();
38240 var box = this.el.getBox();
38242 var sh = this.split.el.getHeight();
38249 updateBox : function(box){
38250 if(this.split && !this.collapsed){
38251 var sh = this.split.el.getHeight();
38254 this.split.el.setLeft(box.x);
38255 this.split.el.setTop(box.y-sh);
38256 this.split.el.setWidth(box.width);
38258 if(this.collapsed){
38259 this.updateBody(box.width, null);
38261 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38265 Roo.bootstrap.layout.East = function(config){
38266 config.region = "east";
38267 config.cursor = "e-resize";
38268 Roo.bootstrap.layout.Split.call(this, config);
38270 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
38271 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
38272 this.split.el.addClass("roo-layout-split-h");
38274 var size = config.initialSize || config.width;
38275 if(typeof size != "undefined"){
38276 this.el.setWidth(size);
38279 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
38280 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
38281 getBox : function(){
38282 if(this.collapsed){
38283 return this.collapsedEl.getBox();
38285 var box = this.el.getBox();
38287 var sw = this.split.el.getWidth();
38294 updateBox : function(box){
38295 if(this.split && !this.collapsed){
38296 var sw = this.split.el.getWidth();
38298 this.split.el.setLeft(box.x);
38299 this.split.el.setTop(box.y);
38300 this.split.el.setHeight(box.height);
38303 if(this.collapsed){
38304 this.updateBody(null, box.height);
38306 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38310 Roo.bootstrap.layout.West = function(config){
38311 config.region = "west";
38312 config.cursor = "w-resize";
38314 Roo.bootstrap.layout.Split.call(this, config);
38316 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
38317 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
38318 this.split.el.addClass("roo-layout-split-h");
38322 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
38323 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
38325 onRender: function(ctr, pos)
38327 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
38328 var size = this.config.initialSize || this.config.width;
38329 if(typeof size != "undefined"){
38330 this.el.setWidth(size);
38334 getBox : function(){
38335 if(this.collapsed){
38336 return this.collapsedEl.getBox();
38338 var box = this.el.getBox();
38340 box.width += this.split.el.getWidth();
38345 updateBox : function(box){
38346 if(this.split && !this.collapsed){
38347 var sw = this.split.el.getWidth();
38349 this.split.el.setLeft(box.x+box.width);
38350 this.split.el.setTop(box.y);
38351 this.split.el.setHeight(box.height);
38353 if(this.collapsed){
38354 this.updateBody(null, box.height);
38356 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38358 });Roo.namespace("Roo.bootstrap.panel");/*
38360 * Ext JS Library 1.1.1
38361 * Copyright(c) 2006-2007, Ext JS, LLC.
38363 * Originally Released Under LGPL - original licence link has changed is not relivant.
38366 * <script type="text/javascript">
38369 * @class Roo.ContentPanel
38370 * @extends Roo.util.Observable
38371 * A basic ContentPanel element.
38372 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
38373 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
38374 * @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
38375 * @cfg {Boolean} closable True if the panel can be closed/removed
38376 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
38377 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
38378 * @cfg {Toolbar} toolbar A toolbar for this panel
38379 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
38380 * @cfg {String} title The title for this panel
38381 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
38382 * @cfg {String} url Calls {@link #setUrl} with this value
38383 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
38384 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
38385 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
38386 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
38387 * @cfg {Boolean} badges render the badges
38390 * Create a new ContentPanel.
38391 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
38392 * @param {String/Object} config A string to set only the title or a config object
38393 * @param {String} content (optional) Set the HTML content for this panel
38394 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
38396 Roo.bootstrap.panel.Content = function( config){
38398 this.tpl = config.tpl || false;
38400 var el = config.el;
38401 var content = config.content;
38403 if(config.autoCreate){ // xtype is available if this is called from factory
38406 this.el = Roo.get(el);
38407 if(!this.el && config && config.autoCreate){
38408 if(typeof config.autoCreate == "object"){
38409 if(!config.autoCreate.id){
38410 config.autoCreate.id = config.id||el;
38412 this.el = Roo.DomHelper.append(document.body,
38413 config.autoCreate, true);
38415 var elcfg = { tag: "div",
38416 cls: "roo-layout-inactive-content",
38420 elcfg.html = config.html;
38424 this.el = Roo.DomHelper.append(document.body, elcfg , true);
38427 this.closable = false;
38428 this.loaded = false;
38429 this.active = false;
38432 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
38434 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
38436 this.wrapEl = this.el; //this.el.wrap();
38438 if (config.toolbar.items) {
38439 ti = config.toolbar.items ;
38440 delete config.toolbar.items ;
38444 this.toolbar.render(this.wrapEl, 'before');
38445 for(var i =0;i < ti.length;i++) {
38446 // Roo.log(['add child', items[i]]);
38447 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
38449 this.toolbar.items = nitems;
38450 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
38451 delete config.toolbar;
38455 // xtype created footer. - not sure if will work as we normally have to render first..
38456 if (this.footer && !this.footer.el && this.footer.xtype) {
38457 if (!this.wrapEl) {
38458 this.wrapEl = this.el.wrap();
38461 this.footer.container = this.wrapEl.createChild();
38463 this.footer = Roo.factory(this.footer, Roo);
38468 if(typeof config == "string"){
38469 this.title = config;
38471 Roo.apply(this, config);
38475 this.resizeEl = Roo.get(this.resizeEl, true);
38477 this.resizeEl = this.el;
38479 // handle view.xtype
38487 * Fires when this panel is activated.
38488 * @param {Roo.ContentPanel} this
38492 * @event deactivate
38493 * Fires when this panel is activated.
38494 * @param {Roo.ContentPanel} this
38496 "deactivate" : true,
38500 * Fires when this panel is resized if fitToFrame is true.
38501 * @param {Roo.ContentPanel} this
38502 * @param {Number} width The width after any component adjustments
38503 * @param {Number} height The height after any component adjustments
38509 * Fires when this tab is created
38510 * @param {Roo.ContentPanel} this
38521 if(this.autoScroll){
38522 this.resizeEl.setStyle("overflow", "auto");
38524 // fix randome scrolling
38525 //this.el.on('scroll', function() {
38526 // Roo.log('fix random scolling');
38527 // this.scrollTo('top',0);
38530 content = content || this.content;
38532 this.setContent(content);
38534 if(config && config.url){
38535 this.setUrl(this.url, this.params, this.loadOnce);
38540 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
38542 if (this.view && typeof(this.view.xtype) != 'undefined') {
38543 this.view.el = this.el.appendChild(document.createElement("div"));
38544 this.view = Roo.factory(this.view);
38545 this.view.render && this.view.render(false, '');
38549 this.fireEvent('render', this);
38552 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
38556 setRegion : function(region){
38557 this.region = region;
38558 this.setActiveClass(region && !this.background);
38562 setActiveClass: function(state)
38565 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
38566 this.el.setStyle('position','relative');
38568 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
38569 this.el.setStyle('position', 'absolute');
38574 * Returns the toolbar for this Panel if one was configured.
38575 * @return {Roo.Toolbar}
38577 getToolbar : function(){
38578 return this.toolbar;
38581 setActiveState : function(active)
38583 this.active = active;
38584 this.setActiveClass(active);
38586 if(this.fireEvent("deactivate", this) === false){
38591 this.fireEvent("activate", this);
38595 * Updates this panel's element
38596 * @param {String} content The new content
38597 * @param {Boolean} loadScripts (optional) true to look for and process scripts
38599 setContent : function(content, loadScripts){
38600 this.el.update(content, loadScripts);
38603 ignoreResize : function(w, h){
38604 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
38607 this.lastSize = {width: w, height: h};
38612 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
38613 * @return {Roo.UpdateManager} The UpdateManager
38615 getUpdateManager : function(){
38616 return this.el.getUpdateManager();
38619 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
38620 * @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:
38623 url: "your-url.php",
38624 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
38625 callback: yourFunction,
38626 scope: yourObject, //(optional scope)
38629 text: "Loading...",
38634 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
38635 * 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.
38636 * @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}
38637 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
38638 * @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.
38639 * @return {Roo.ContentPanel} this
38642 var um = this.el.getUpdateManager();
38643 um.update.apply(um, arguments);
38649 * 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.
38650 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
38651 * @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)
38652 * @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)
38653 * @return {Roo.UpdateManager} The UpdateManager
38655 setUrl : function(url, params, loadOnce){
38656 if(this.refreshDelegate){
38657 this.removeListener("activate", this.refreshDelegate);
38659 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38660 this.on("activate", this.refreshDelegate);
38661 return this.el.getUpdateManager();
38664 _handleRefresh : function(url, params, loadOnce){
38665 if(!loadOnce || !this.loaded){
38666 var updater = this.el.getUpdateManager();
38667 updater.update(url, params, this._setLoaded.createDelegate(this));
38671 _setLoaded : function(){
38672 this.loaded = true;
38676 * Returns this panel's id
38679 getId : function(){
38684 * Returns this panel's element - used by regiosn to add.
38685 * @return {Roo.Element}
38687 getEl : function(){
38688 return this.wrapEl || this.el;
38693 adjustForComponents : function(width, height)
38695 //Roo.log('adjustForComponents ');
38696 if(this.resizeEl != this.el){
38697 width -= this.el.getFrameWidth('lr');
38698 height -= this.el.getFrameWidth('tb');
38701 var te = this.toolbar.getEl();
38702 te.setWidth(width);
38703 height -= te.getHeight();
38706 var te = this.footer.getEl();
38707 te.setWidth(width);
38708 height -= te.getHeight();
38712 if(this.adjustments){
38713 width += this.adjustments[0];
38714 height += this.adjustments[1];
38716 return {"width": width, "height": height};
38719 setSize : function(width, height){
38720 if(this.fitToFrame && !this.ignoreResize(width, height)){
38721 if(this.fitContainer && this.resizeEl != this.el){
38722 this.el.setSize(width, height);
38724 var size = this.adjustForComponents(width, height);
38725 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
38726 this.fireEvent('resize', this, size.width, size.height);
38731 * Returns this panel's title
38734 getTitle : function(){
38736 if (typeof(this.title) != 'object') {
38741 for (var k in this.title) {
38742 if (!this.title.hasOwnProperty(k)) {
38746 if (k.indexOf('-') >= 0) {
38747 var s = k.split('-');
38748 for (var i = 0; i<s.length; i++) {
38749 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
38752 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
38759 * Set this panel's title
38760 * @param {String} title
38762 setTitle : function(title){
38763 this.title = title;
38765 this.region.updatePanelTitle(this, title);
38770 * Returns true is this panel was configured to be closable
38771 * @return {Boolean}
38773 isClosable : function(){
38774 return this.closable;
38777 beforeSlide : function(){
38779 this.resizeEl.clip();
38782 afterSlide : function(){
38784 this.resizeEl.unclip();
38788 * Force a content refresh from the URL specified in the {@link #setUrl} method.
38789 * Will fail silently if the {@link #setUrl} method has not been called.
38790 * This does not activate the panel, just updates its content.
38792 refresh : function(){
38793 if(this.refreshDelegate){
38794 this.loaded = false;
38795 this.refreshDelegate();
38800 * Destroys this panel
38802 destroy : function(){
38803 this.el.removeAllListeners();
38804 var tempEl = document.createElement("span");
38805 tempEl.appendChild(this.el.dom);
38806 tempEl.innerHTML = "";
38812 * form - if the content panel contains a form - this is a reference to it.
38813 * @type {Roo.form.Form}
38817 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
38818 * This contains a reference to it.
38824 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
38834 * @param {Object} cfg Xtype definition of item to add.
38838 getChildContainer: function () {
38839 return this.getEl();
38844 var ret = new Roo.factory(cfg);
38849 if (cfg.xtype.match(/^Form$/)) {
38852 //if (this.footer) {
38853 // el = this.footer.container.insertSibling(false, 'before');
38855 el = this.el.createChild();
38858 this.form = new Roo.form.Form(cfg);
38861 if ( this.form.allItems.length) {
38862 this.form.render(el.dom);
38866 // should only have one of theses..
38867 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
38868 // views.. should not be just added - used named prop 'view''
38870 cfg.el = this.el.appendChild(document.createElement("div"));
38873 var ret = new Roo.factory(cfg);
38875 ret.render && ret.render(false, ''); // render blank..
38885 * @class Roo.bootstrap.panel.Grid
38886 * @extends Roo.bootstrap.panel.Content
38888 * Create a new GridPanel.
38889 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
38890 * @param {Object} config A the config object
38896 Roo.bootstrap.panel.Grid = function(config)
38900 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
38901 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
38903 config.el = this.wrapper;
38904 //this.el = this.wrapper;
38906 if (config.container) {
38907 // ctor'ed from a Border/panel.grid
38910 this.wrapper.setStyle("overflow", "hidden");
38911 this.wrapper.addClass('roo-grid-container');
38916 if(config.toolbar){
38917 var tool_el = this.wrapper.createChild();
38918 this.toolbar = Roo.factory(config.toolbar);
38920 if (config.toolbar.items) {
38921 ti = config.toolbar.items ;
38922 delete config.toolbar.items ;
38926 this.toolbar.render(tool_el);
38927 for(var i =0;i < ti.length;i++) {
38928 // Roo.log(['add child', items[i]]);
38929 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
38931 this.toolbar.items = nitems;
38933 delete config.toolbar;
38936 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
38937 config.grid.scrollBody = true;;
38938 config.grid.monitorWindowResize = false; // turn off autosizing
38939 config.grid.autoHeight = false;
38940 config.grid.autoWidth = false;
38942 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
38944 if (config.background) {
38945 // render grid on panel activation (if panel background)
38946 this.on('activate', function(gp) {
38947 if (!gp.grid.rendered) {
38948 gp.grid.render(this.wrapper);
38949 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
38954 this.grid.render(this.wrapper);
38955 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
38958 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
38959 // ??? needed ??? config.el = this.wrapper;
38964 // xtype created footer. - not sure if will work as we normally have to render first..
38965 if (this.footer && !this.footer.el && this.footer.xtype) {
38967 var ctr = this.grid.getView().getFooterPanel(true);
38968 this.footer.dataSource = this.grid.dataSource;
38969 this.footer = Roo.factory(this.footer, Roo);
38970 this.footer.render(ctr);
38980 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
38981 getId : function(){
38982 return this.grid.id;
38986 * Returns the grid for this panel
38987 * @return {Roo.bootstrap.Table}
38989 getGrid : function(){
38993 setSize : function(width, height){
38994 if(!this.ignoreResize(width, height)){
38995 var grid = this.grid;
38996 var size = this.adjustForComponents(width, height);
38997 var gridel = grid.getGridEl();
38998 gridel.setSize(size.width, size.height);
39000 var thd = grid.getGridEl().select('thead',true).first();
39001 var tbd = grid.getGridEl().select('tbody', true).first();
39003 tbd.setSize(width, height - thd.getHeight());
39012 beforeSlide : function(){
39013 this.grid.getView().scroller.clip();
39016 afterSlide : function(){
39017 this.grid.getView().scroller.unclip();
39020 destroy : function(){
39021 this.grid.destroy();
39023 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
39028 * @class Roo.bootstrap.panel.Nest
39029 * @extends Roo.bootstrap.panel.Content
39031 * Create a new Panel, that can contain a layout.Border.
39034 * @param {Roo.BorderLayout} layout The layout for this panel
39035 * @param {String/Object} config A string to set only the title or a config object
39037 Roo.bootstrap.panel.Nest = function(config)
39039 // construct with only one argument..
39040 /* FIXME - implement nicer consturctors
39041 if (layout.layout) {
39043 layout = config.layout;
39044 delete config.layout;
39046 if (layout.xtype && !layout.getEl) {
39047 // then layout needs constructing..
39048 layout = Roo.factory(layout, Roo);
39052 config.el = config.layout.getEl();
39054 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
39056 config.layout.monitorWindowResize = false; // turn off autosizing
39057 this.layout = config.layout;
39058 this.layout.getEl().addClass("roo-layout-nested-layout");
39059 this.layout.parent = this;
39066 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
39068 setSize : function(width, height){
39069 if(!this.ignoreResize(width, height)){
39070 var size = this.adjustForComponents(width, height);
39071 var el = this.layout.getEl();
39072 if (size.height < 1) {
39073 el.setWidth(size.width);
39075 el.setSize(size.width, size.height);
39077 var touch = el.dom.offsetWidth;
39078 this.layout.layout();
39079 // ie requires a double layout on the first pass
39080 if(Roo.isIE && !this.initialized){
39081 this.initialized = true;
39082 this.layout.layout();
39087 // activate all subpanels if not currently active..
39089 setActiveState : function(active){
39090 this.active = active;
39091 this.setActiveClass(active);
39094 this.fireEvent("deactivate", this);
39098 this.fireEvent("activate", this);
39099 // not sure if this should happen before or after..
39100 if (!this.layout) {
39101 return; // should not happen..
39104 for (var r in this.layout.regions) {
39105 reg = this.layout.getRegion(r);
39106 if (reg.getActivePanel()) {
39107 //reg.showPanel(reg.getActivePanel()); // force it to activate..
39108 reg.setActivePanel(reg.getActivePanel());
39111 if (!reg.panels.length) {
39114 reg.showPanel(reg.getPanel(0));
39123 * Returns the nested BorderLayout for this panel
39124 * @return {Roo.BorderLayout}
39126 getLayout : function(){
39127 return this.layout;
39131 * Adds a xtype elements to the layout of the nested panel
39135 xtype : 'ContentPanel',
39142 xtype : 'NestedLayoutPanel',
39148 items : [ ... list of content panels or nested layout panels.. ]
39152 * @param {Object} cfg Xtype definition of item to add.
39154 addxtype : function(cfg) {
39155 return this.layout.addxtype(cfg);
39160 * Ext JS Library 1.1.1
39161 * Copyright(c) 2006-2007, Ext JS, LLC.
39163 * Originally Released Under LGPL - original licence link has changed is not relivant.
39166 * <script type="text/javascript">
39169 * @class Roo.TabPanel
39170 * @extends Roo.util.Observable
39171 * A lightweight tab container.
39175 // basic tabs 1, built from existing content
39176 var tabs = new Roo.TabPanel("tabs1");
39177 tabs.addTab("script", "View Script");
39178 tabs.addTab("markup", "View Markup");
39179 tabs.activate("script");
39181 // more advanced tabs, built from javascript
39182 var jtabs = new Roo.TabPanel("jtabs");
39183 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
39185 // set up the UpdateManager
39186 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
39187 var updater = tab2.getUpdateManager();
39188 updater.setDefaultUrl("ajax1.htm");
39189 tab2.on('activate', updater.refresh, updater, true);
39191 // Use setUrl for Ajax loading
39192 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
39193 tab3.setUrl("ajax2.htm", null, true);
39196 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
39199 jtabs.activate("jtabs-1");
39202 * Create a new TabPanel.
39203 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
39204 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
39206 Roo.bootstrap.panel.Tabs = function(config){
39208 * The container element for this TabPanel.
39209 * @type Roo.Element
39211 this.el = Roo.get(config.el);
39214 if(typeof config == "boolean"){
39215 this.tabPosition = config ? "bottom" : "top";
39217 Roo.apply(this, config);
39221 if(this.tabPosition == "bottom"){
39222 // if tabs are at the bottom = create the body first.
39223 this.bodyEl = Roo.get(this.createBody(this.el.dom));
39224 this.el.addClass("roo-tabs-bottom");
39226 // next create the tabs holders
39228 if (this.tabPosition == "west"){
39230 var reg = this.region; // fake it..
39232 if (!reg.mgr.parent) {
39235 reg = reg.mgr.parent.region;
39237 Roo.log("got nest?");
39239 if (reg.mgr.getRegion('west')) {
39240 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
39241 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
39242 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
39243 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
39244 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
39252 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
39253 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
39254 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
39255 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
39260 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
39263 // finally - if tabs are at the top, then create the body last..
39264 if(this.tabPosition != "bottom"){
39265 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
39266 * @type Roo.Element
39268 this.bodyEl = Roo.get(this.createBody(this.el.dom));
39269 this.el.addClass("roo-tabs-top");
39273 this.bodyEl.setStyle("position", "relative");
39275 this.active = null;
39276 this.activateDelegate = this.activate.createDelegate(this);
39281 * Fires when the active tab changes
39282 * @param {Roo.TabPanel} this
39283 * @param {Roo.TabPanelItem} activePanel The new active tab
39287 * @event beforetabchange
39288 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
39289 * @param {Roo.TabPanel} this
39290 * @param {Object} e Set cancel to true on this object to cancel the tab change
39291 * @param {Roo.TabPanelItem} tab The tab being changed to
39293 "beforetabchange" : true
39296 Roo.EventManager.onWindowResize(this.onResize, this);
39297 this.cpad = this.el.getPadding("lr");
39298 this.hiddenCount = 0;
39301 // toolbar on the tabbar support...
39302 if (this.toolbar) {
39303 alert("no toolbar support yet");
39304 this.toolbar = false;
39306 var tcfg = this.toolbar;
39307 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
39308 this.toolbar = new Roo.Toolbar(tcfg);
39309 if (Roo.isSafari) {
39310 var tbl = tcfg.container.child('table', true);
39311 tbl.setAttribute('width', '100%');
39319 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
39322 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
39324 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
39326 tabPosition : "top",
39328 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
39330 currentTabWidth : 0,
39332 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
39336 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
39340 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
39342 preferredTabWidth : 175,
39344 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
39346 resizeTabs : false,
39348 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
39350 monitorResize : true,
39352 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
39354 toolbar : false, // set by caller..
39356 region : false, /// set by caller
39358 disableTooltips : true, // not used yet...
39361 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
39362 * @param {String} id The id of the div to use <b>or create</b>
39363 * @param {String} text The text for the tab
39364 * @param {String} content (optional) Content to put in the TabPanelItem body
39365 * @param {Boolean} closable (optional) True to create a close icon on the tab
39366 * @return {Roo.TabPanelItem} The created TabPanelItem
39368 addTab : function(id, text, content, closable, tpl)
39370 var item = new Roo.bootstrap.panel.TabItem({
39374 closable : closable,
39377 this.addTabItem(item);
39379 item.setContent(content);
39385 * Returns the {@link Roo.TabPanelItem} with the specified id/index
39386 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
39387 * @return {Roo.TabPanelItem}
39389 getTab : function(id){
39390 return this.items[id];
39394 * Hides the {@link Roo.TabPanelItem} with the specified id/index
39395 * @param {String/Number} id The id or index of the TabPanelItem to hide.
39397 hideTab : function(id){
39398 var t = this.items[id];
39401 this.hiddenCount++;
39402 this.autoSizeTabs();
39407 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
39408 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
39410 unhideTab : function(id){
39411 var t = this.items[id];
39413 t.setHidden(false);
39414 this.hiddenCount--;
39415 this.autoSizeTabs();
39420 * Adds an existing {@link Roo.TabPanelItem}.
39421 * @param {Roo.TabPanelItem} item The TabPanelItem to add
39423 addTabItem : function(item)
39425 this.items[item.id] = item;
39426 this.items.push(item);
39427 this.autoSizeTabs();
39428 // if(this.resizeTabs){
39429 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
39430 // this.autoSizeTabs();
39432 // item.autoSize();
39437 * Removes a {@link Roo.TabPanelItem}.
39438 * @param {String/Number} id The id or index of the TabPanelItem to remove.
39440 removeTab : function(id){
39441 var items = this.items;
39442 var tab = items[id];
39443 if(!tab) { return; }
39444 var index = items.indexOf(tab);
39445 if(this.active == tab && items.length > 1){
39446 var newTab = this.getNextAvailable(index);
39451 this.stripEl.dom.removeChild(tab.pnode.dom);
39452 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
39453 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
39455 items.splice(index, 1);
39456 delete this.items[tab.id];
39457 tab.fireEvent("close", tab);
39458 tab.purgeListeners();
39459 this.autoSizeTabs();
39462 getNextAvailable : function(start){
39463 var items = this.items;
39465 // look for a next tab that will slide over to
39466 // replace the one being removed
39467 while(index < items.length){
39468 var item = items[++index];
39469 if(item && !item.isHidden()){
39473 // if one isn't found select the previous tab (on the left)
39476 var item = items[--index];
39477 if(item && !item.isHidden()){
39485 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
39486 * @param {String/Number} id The id or index of the TabPanelItem to disable.
39488 disableTab : function(id){
39489 var tab = this.items[id];
39490 if(tab && this.active != tab){
39496 * Enables a {@link Roo.TabPanelItem} that is disabled.
39497 * @param {String/Number} id The id or index of the TabPanelItem to enable.
39499 enableTab : function(id){
39500 var tab = this.items[id];
39505 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
39506 * @param {String/Number} id The id or index of the TabPanelItem to activate.
39507 * @return {Roo.TabPanelItem} The TabPanelItem.
39509 activate : function(id)
39511 //Roo.log('activite:' + id);
39513 var tab = this.items[id];
39517 if(tab == this.active || tab.disabled){
39521 this.fireEvent("beforetabchange", this, e, tab);
39522 if(e.cancel !== true && !tab.disabled){
39524 this.active.hide();
39526 this.active = this.items[id];
39527 this.active.show();
39528 this.fireEvent("tabchange", this, this.active);
39534 * Gets the active {@link Roo.TabPanelItem}.
39535 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
39537 getActiveTab : function(){
39538 return this.active;
39542 * Updates the tab body element to fit the height of the container element
39543 * for overflow scrolling
39544 * @param {Number} targetHeight (optional) Override the starting height from the elements height
39546 syncHeight : function(targetHeight){
39547 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
39548 var bm = this.bodyEl.getMargins();
39549 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
39550 this.bodyEl.setHeight(newHeight);
39554 onResize : function(){
39555 if(this.monitorResize){
39556 this.autoSizeTabs();
39561 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
39563 beginUpdate : function(){
39564 this.updating = true;
39568 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
39570 endUpdate : function(){
39571 this.updating = false;
39572 this.autoSizeTabs();
39576 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
39578 autoSizeTabs : function()
39580 var count = this.items.length;
39581 var vcount = count - this.hiddenCount;
39584 this.stripEl.hide();
39586 this.stripEl.show();
39589 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
39594 var w = Math.max(this.el.getWidth() - this.cpad, 10);
39595 var availWidth = Math.floor(w / vcount);
39596 var b = this.stripBody;
39597 if(b.getWidth() > w){
39598 var tabs = this.items;
39599 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
39600 if(availWidth < this.minTabWidth){
39601 /*if(!this.sleft){ // incomplete scrolling code
39602 this.createScrollButtons();
39605 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
39608 if(this.currentTabWidth < this.preferredTabWidth){
39609 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
39615 * Returns the number of tabs in this TabPanel.
39618 getCount : function(){
39619 return this.items.length;
39623 * Resizes all the tabs to the passed width
39624 * @param {Number} The new width
39626 setTabWidth : function(width){
39627 this.currentTabWidth = width;
39628 for(var i = 0, len = this.items.length; i < len; i++) {
39629 if(!this.items[i].isHidden()) {
39630 this.items[i].setWidth(width);
39636 * Destroys this TabPanel
39637 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
39639 destroy : function(removeEl){
39640 Roo.EventManager.removeResizeListener(this.onResize, this);
39641 for(var i = 0, len = this.items.length; i < len; i++){
39642 this.items[i].purgeListeners();
39644 if(removeEl === true){
39645 this.el.update("");
39650 createStrip : function(container)
39652 var strip = document.createElement("nav");
39653 strip.className = Roo.bootstrap.version == 4 ?
39654 "navbar-light bg-light" :
39655 "navbar navbar-default"; //"x-tabs-wrap";
39656 container.appendChild(strip);
39660 createStripList : function(strip)
39662 // div wrapper for retard IE
39663 // returns the "tr" element.
39664 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
39665 //'<div class="x-tabs-strip-wrap">'+
39666 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
39667 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
39668 return strip.firstChild; //.firstChild.firstChild.firstChild;
39670 createBody : function(container)
39672 var body = document.createElement("div");
39673 Roo.id(body, "tab-body");
39674 //Roo.fly(body).addClass("x-tabs-body");
39675 Roo.fly(body).addClass("tab-content");
39676 container.appendChild(body);
39679 createItemBody :function(bodyEl, id){
39680 var body = Roo.getDom(id);
39682 body = document.createElement("div");
39685 //Roo.fly(body).addClass("x-tabs-item-body");
39686 Roo.fly(body).addClass("tab-pane");
39687 bodyEl.insertBefore(body, bodyEl.firstChild);
39691 createStripElements : function(stripEl, text, closable, tpl)
39693 var td = document.createElement("li"); // was td..
39694 td.className = 'nav-item';
39696 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
39699 stripEl.appendChild(td);
39701 td.className = "x-tabs-closable";
39702 if(!this.closeTpl){
39703 this.closeTpl = new Roo.Template(
39704 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
39705 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
39706 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
39709 var el = this.closeTpl.overwrite(td, {"text": text});
39710 var close = el.getElementsByTagName("div")[0];
39711 var inner = el.getElementsByTagName("em")[0];
39712 return {"el": el, "close": close, "inner": inner};
39715 // not sure what this is..
39716 // if(!this.tabTpl){
39717 //this.tabTpl = new Roo.Template(
39718 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
39719 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
39721 // this.tabTpl = new Roo.Template(
39722 // '<a href="#">' +
39723 // '<span unselectable="on"' +
39724 // (this.disableTooltips ? '' : ' title="{text}"') +
39725 // ' >{text}</span></a>'
39731 var template = tpl || this.tabTpl || false;
39734 template = new Roo.Template(
39735 Roo.bootstrap.version == 4 ?
39737 '<a class="nav-link" href="#" unselectable="on"' +
39738 (this.disableTooltips ? '' : ' title="{text}"') +
39741 '<a class="nav-link" href="#">' +
39742 '<span unselectable="on"' +
39743 (this.disableTooltips ? '' : ' title="{text}"') +
39744 ' >{text}</span></a>'
39749 switch (typeof(template)) {
39753 template = new Roo.Template(template);
39759 var el = template.overwrite(td, {"text": text});
39761 var inner = el.getElementsByTagName("span")[0];
39763 return {"el": el, "inner": inner};
39771 * @class Roo.TabPanelItem
39772 * @extends Roo.util.Observable
39773 * Represents an individual item (tab plus body) in a TabPanel.
39774 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
39775 * @param {String} id The id of this TabPanelItem
39776 * @param {String} text The text for the tab of this TabPanelItem
39777 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
39779 Roo.bootstrap.panel.TabItem = function(config){
39781 * The {@link Roo.TabPanel} this TabPanelItem belongs to
39782 * @type Roo.TabPanel
39784 this.tabPanel = config.panel;
39786 * The id for this TabPanelItem
39789 this.id = config.id;
39791 this.disabled = false;
39793 this.text = config.text;
39795 this.loaded = false;
39796 this.closable = config.closable;
39799 * The body element for this TabPanelItem.
39800 * @type Roo.Element
39802 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
39803 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
39804 this.bodyEl.setStyle("display", "block");
39805 this.bodyEl.setStyle("zoom", "1");
39806 //this.hideAction();
39808 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
39810 this.el = Roo.get(els.el);
39811 this.inner = Roo.get(els.inner, true);
39812 this.textEl = Roo.bootstrap.version == 4 ?
39813 this.el : Roo.get(this.el.dom.firstChild, true);
39815 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
39816 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
39819 // this.el.on("mousedown", this.onTabMouseDown, this);
39820 this.el.on("click", this.onTabClick, this);
39822 if(config.closable){
39823 var c = Roo.get(els.close, true);
39824 c.dom.title = this.closeText;
39825 c.addClassOnOver("close-over");
39826 c.on("click", this.closeClick, this);
39832 * Fires when this tab becomes the active tab.
39833 * @param {Roo.TabPanel} tabPanel The parent TabPanel
39834 * @param {Roo.TabPanelItem} this
39838 * @event beforeclose
39839 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
39840 * @param {Roo.TabPanelItem} this
39841 * @param {Object} e Set cancel to true on this object to cancel the close.
39843 "beforeclose": true,
39846 * Fires when this tab is closed.
39847 * @param {Roo.TabPanelItem} this
39851 * @event deactivate
39852 * Fires when this tab is no longer the active tab.
39853 * @param {Roo.TabPanel} tabPanel The parent TabPanel
39854 * @param {Roo.TabPanelItem} this
39856 "deactivate" : true
39858 this.hidden = false;
39860 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
39863 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
39865 purgeListeners : function(){
39866 Roo.util.Observable.prototype.purgeListeners.call(this);
39867 this.el.removeAllListeners();
39870 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
39873 this.status_node.addClass("active");
39876 this.tabPanel.stripWrap.repaint();
39878 this.fireEvent("activate", this.tabPanel, this);
39882 * Returns true if this tab is the active tab.
39883 * @return {Boolean}
39885 isActive : function(){
39886 return this.tabPanel.getActiveTab() == this;
39890 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
39893 this.status_node.removeClass("active");
39895 this.fireEvent("deactivate", this.tabPanel, this);
39898 hideAction : function(){
39899 this.bodyEl.hide();
39900 this.bodyEl.setStyle("position", "absolute");
39901 this.bodyEl.setLeft("-20000px");
39902 this.bodyEl.setTop("-20000px");
39905 showAction : function(){
39906 this.bodyEl.setStyle("position", "relative");
39907 this.bodyEl.setTop("");
39908 this.bodyEl.setLeft("");
39909 this.bodyEl.show();
39913 * Set the tooltip for the tab.
39914 * @param {String} tooltip The tab's tooltip
39916 setTooltip : function(text){
39917 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
39918 this.textEl.dom.qtip = text;
39919 this.textEl.dom.removeAttribute('title');
39921 this.textEl.dom.title = text;
39925 onTabClick : function(e){
39926 e.preventDefault();
39927 this.tabPanel.activate(this.id);
39930 onTabMouseDown : function(e){
39931 e.preventDefault();
39932 this.tabPanel.activate(this.id);
39935 getWidth : function(){
39936 return this.inner.getWidth();
39939 setWidth : function(width){
39940 var iwidth = width - this.linode.getPadding("lr");
39941 this.inner.setWidth(iwidth);
39942 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
39943 this.linode.setWidth(width);
39947 * Show or hide the tab
39948 * @param {Boolean} hidden True to hide or false to show.
39950 setHidden : function(hidden){
39951 this.hidden = hidden;
39952 this.linode.setStyle("display", hidden ? "none" : "");
39956 * Returns true if this tab is "hidden"
39957 * @return {Boolean}
39959 isHidden : function(){
39960 return this.hidden;
39964 * Returns the text for this tab
39967 getText : function(){
39971 autoSize : function(){
39972 //this.el.beginMeasure();
39973 this.textEl.setWidth(1);
39975 * #2804 [new] Tabs in Roojs
39976 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
39978 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
39979 //this.el.endMeasure();
39983 * Sets the text for the tab (Note: this also sets the tooltip text)
39984 * @param {String} text The tab's text and tooltip
39986 setText : function(text){
39988 this.textEl.update(text);
39989 this.setTooltip(text);
39990 //if(!this.tabPanel.resizeTabs){
39991 // this.autoSize();
39995 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
39997 activate : function(){
39998 this.tabPanel.activate(this.id);
40002 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
40004 disable : function(){
40005 if(this.tabPanel.active != this){
40006 this.disabled = true;
40007 this.status_node.addClass("disabled");
40012 * Enables this TabPanelItem if it was previously disabled.
40014 enable : function(){
40015 this.disabled = false;
40016 this.status_node.removeClass("disabled");
40020 * Sets the content for this TabPanelItem.
40021 * @param {String} content The content
40022 * @param {Boolean} loadScripts true to look for and load scripts
40024 setContent : function(content, loadScripts){
40025 this.bodyEl.update(content, loadScripts);
40029 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
40030 * @return {Roo.UpdateManager} The UpdateManager
40032 getUpdateManager : function(){
40033 return this.bodyEl.getUpdateManager();
40037 * Set a URL to be used to load the content for this TabPanelItem.
40038 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
40039 * @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)
40040 * @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)
40041 * @return {Roo.UpdateManager} The UpdateManager
40043 setUrl : function(url, params, loadOnce){
40044 if(this.refreshDelegate){
40045 this.un('activate', this.refreshDelegate);
40047 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
40048 this.on("activate", this.refreshDelegate);
40049 return this.bodyEl.getUpdateManager();
40053 _handleRefresh : function(url, params, loadOnce){
40054 if(!loadOnce || !this.loaded){
40055 var updater = this.bodyEl.getUpdateManager();
40056 updater.update(url, params, this._setLoaded.createDelegate(this));
40061 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
40062 * Will fail silently if the setUrl method has not been called.
40063 * This does not activate the panel, just updates its content.
40065 refresh : function(){
40066 if(this.refreshDelegate){
40067 this.loaded = false;
40068 this.refreshDelegate();
40073 _setLoaded : function(){
40074 this.loaded = true;
40078 closeClick : function(e){
40081 this.fireEvent("beforeclose", this, o);
40082 if(o.cancel !== true){
40083 this.tabPanel.removeTab(this.id);
40087 * The text displayed in the tooltip for the close icon.
40090 closeText : "Close this tab"
40093 * This script refer to:
40094 * Title: International Telephone Input
40095 * Author: Jack O'Connor
40096 * Code version: v12.1.12
40097 * Availability: https://github.com/jackocnr/intl-tel-input.git
40100 Roo.bootstrap.PhoneInputData = function() {
40103 "Afghanistan (افغانستان)",
40108 "Albania (Shqipëri)",
40113 "Algeria (الجزائر)",
40138 "Antigua and Barbuda",
40148 "Armenia (Հայաստան)",
40164 "Austria (Österreich)",
40169 "Azerbaijan (Azərbaycan)",
40179 "Bahrain (البحرين)",
40184 "Bangladesh (বাংলাদেশ)",
40194 "Belarus (Беларусь)",
40199 "Belgium (België)",
40229 "Bosnia and Herzegovina (Босна и Херцеговина)",
40244 "British Indian Ocean Territory",
40249 "British Virgin Islands",
40259 "Bulgaria (България)",
40269 "Burundi (Uburundi)",
40274 "Cambodia (កម្ពុជា)",
40279 "Cameroon (Cameroun)",
40288 ["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"]
40291 "Cape Verde (Kabu Verdi)",
40296 "Caribbean Netherlands",
40307 "Central African Republic (République centrafricaine)",
40327 "Christmas Island",
40333 "Cocos (Keeling) Islands",
40344 "Comoros (جزر القمر)",
40349 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
40354 "Congo (Republic) (Congo-Brazzaville)",
40374 "Croatia (Hrvatska)",
40395 "Czech Republic (Česká republika)",
40400 "Denmark (Danmark)",
40415 "Dominican Republic (República Dominicana)",
40419 ["809", "829", "849"]
40437 "Equatorial Guinea (Guinea Ecuatorial)",
40457 "Falkland Islands (Islas Malvinas)",
40462 "Faroe Islands (Føroyar)",
40483 "French Guiana (Guyane française)",
40488 "French Polynesia (Polynésie française)",
40503 "Georgia (საქართველო)",
40508 "Germany (Deutschland)",
40528 "Greenland (Kalaallit Nunaat)",
40565 "Guinea-Bissau (Guiné Bissau)",
40590 "Hungary (Magyarország)",
40595 "Iceland (Ísland)",
40615 "Iraq (العراق)",
40631 "Israel (ישראל)",
40658 "Jordan (الأردن)",
40663 "Kazakhstan (Казахстан)",
40684 "Kuwait (الكويت)",
40689 "Kyrgyzstan (Кыргызстан)",
40699 "Latvia (Latvija)",
40704 "Lebanon (لبنان)",
40719 "Libya (ليبيا)",
40729 "Lithuania (Lietuva)",
40744 "Macedonia (FYROM) (Македонија)",
40749 "Madagascar (Madagasikara)",
40779 "Marshall Islands",
40789 "Mauritania (موريتانيا)",
40794 "Mauritius (Moris)",
40815 "Moldova (Republica Moldova)",
40825 "Mongolia (Монгол)",
40830 "Montenegro (Crna Gora)",
40840 "Morocco (المغرب)",
40846 "Mozambique (Moçambique)",
40851 "Myanmar (Burma) (မြန်မာ)",
40856 "Namibia (Namibië)",
40871 "Netherlands (Nederland)",
40876 "New Caledonia (Nouvelle-Calédonie)",
40911 "North Korea (조선 민주주의 인민 공화국)",
40916 "Northern Mariana Islands",
40932 "Pakistan (پاکستان)",
40942 "Palestine (فلسطين)",
40952 "Papua New Guinea",
40994 "Réunion (La Réunion)",
41000 "Romania (România)",
41016 "Saint Barthélemy",
41027 "Saint Kitts and Nevis",
41037 "Saint Martin (Saint-Martin (partie française))",
41043 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
41048 "Saint Vincent and the Grenadines",
41063 "São Tomé and Príncipe (São Tomé e Príncipe)",
41068 "Saudi Arabia (المملكة العربية السعودية)",
41073 "Senegal (Sénégal)",
41103 "Slovakia (Slovensko)",
41108 "Slovenia (Slovenija)",
41118 "Somalia (Soomaaliya)",
41128 "South Korea (대한민국)",
41133 "South Sudan (جنوب السودان)",
41143 "Sri Lanka (ශ්රී ලංකාව)",
41148 "Sudan (السودان)",
41158 "Svalbard and Jan Mayen",
41169 "Sweden (Sverige)",
41174 "Switzerland (Schweiz)",
41179 "Syria (سوريا)",
41224 "Trinidad and Tobago",
41229 "Tunisia (تونس)",
41234 "Turkey (Türkiye)",
41244 "Turks and Caicos Islands",
41254 "U.S. Virgin Islands",
41264 "Ukraine (Україна)",
41269 "United Arab Emirates (الإمارات العربية المتحدة)",
41291 "Uzbekistan (Oʻzbekiston)",
41301 "Vatican City (Città del Vaticano)",
41312 "Vietnam (Việt Nam)",
41317 "Wallis and Futuna (Wallis-et-Futuna)",
41322 "Western Sahara (الصحراء الغربية)",
41328 "Yemen (اليمن)",
41352 * This script refer to:
41353 * Title: International Telephone Input
41354 * Author: Jack O'Connor
41355 * Code version: v12.1.12
41356 * Availability: https://github.com/jackocnr/intl-tel-input.git
41360 * @class Roo.bootstrap.PhoneInput
41361 * @extends Roo.bootstrap.TriggerField
41362 * An input with International dial-code selection
41364 * @cfg {String} defaultDialCode default '+852'
41365 * @cfg {Array} preferedCountries default []
41368 * Create a new PhoneInput.
41369 * @param {Object} config Configuration options
41372 Roo.bootstrap.PhoneInput = function(config) {
41373 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
41376 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
41378 listWidth: undefined,
41380 selectedClass: 'active',
41382 invalidClass : "has-warning",
41384 validClass: 'has-success',
41386 allowed: '0123456789',
41391 * @cfg {String} defaultDialCode The default dial code when initializing the input
41393 defaultDialCode: '+852',
41396 * @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
41398 preferedCountries: false,
41400 getAutoCreate : function()
41402 var data = Roo.bootstrap.PhoneInputData();
41403 var align = this.labelAlign || this.parentLabelAlign();
41406 this.allCountries = [];
41407 this.dialCodeMapping = [];
41409 for (var i = 0; i < data.length; i++) {
41411 this.allCountries[i] = {
41415 priority: c[3] || 0,
41416 areaCodes: c[4] || null
41418 this.dialCodeMapping[c[2]] = {
41421 priority: c[3] || 0,
41422 areaCodes: c[4] || null
41434 // type: 'number', -- do not use number - we get the flaky up/down arrows.
41435 maxlength: this.max_length,
41436 cls : 'form-control tel-input',
41437 autocomplete: 'new-password'
41440 var hiddenInput = {
41443 cls: 'hidden-tel-input'
41447 hiddenInput.name = this.name;
41450 if (this.disabled) {
41451 input.disabled = true;
41454 var flag_container = {
41471 cls: this.hasFeedback ? 'has-feedback' : '',
41477 cls: 'dial-code-holder',
41484 cls: 'roo-select2-container input-group',
41491 if (this.fieldLabel.length) {
41494 tooltip: 'This field is required'
41500 cls: 'control-label',
41506 html: this.fieldLabel
41509 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41515 if(this.indicatorpos == 'right') {
41516 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41523 if(align == 'left') {
41531 if(this.labelWidth > 12){
41532 label.style = "width: " + this.labelWidth + 'px';
41534 if(this.labelWidth < 13 && this.labelmd == 0){
41535 this.labelmd = this.labelWidth;
41537 if(this.labellg > 0){
41538 label.cls += ' col-lg-' + this.labellg;
41539 input.cls += ' col-lg-' + (12 - this.labellg);
41541 if(this.labelmd > 0){
41542 label.cls += ' col-md-' + this.labelmd;
41543 container.cls += ' col-md-' + (12 - this.labelmd);
41545 if(this.labelsm > 0){
41546 label.cls += ' col-sm-' + this.labelsm;
41547 container.cls += ' col-sm-' + (12 - this.labelsm);
41549 if(this.labelxs > 0){
41550 label.cls += ' col-xs-' + this.labelxs;
41551 container.cls += ' col-xs-' + (12 - this.labelxs);
41561 var settings = this;
41563 ['xs','sm','md','lg'].map(function(size){
41564 if (settings[size]) {
41565 cfg.cls += ' col-' + size + '-' + settings[size];
41569 this.store = new Roo.data.Store({
41570 proxy : new Roo.data.MemoryProxy({}),
41571 reader : new Roo.data.JsonReader({
41582 'name' : 'dialCode',
41586 'name' : 'priority',
41590 'name' : 'areaCodes',
41597 if(!this.preferedCountries) {
41598 this.preferedCountries = [
41605 var p = this.preferedCountries.reverse();
41608 for (var i = 0; i < p.length; i++) {
41609 for (var j = 0; j < this.allCountries.length; j++) {
41610 if(this.allCountries[j].iso2 == p[i]) {
41611 var t = this.allCountries[j];
41612 this.allCountries.splice(j,1);
41613 this.allCountries.unshift(t);
41619 this.store.proxy.data = {
41621 data: this.allCountries
41627 initEvents : function()
41630 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
41632 this.indicator = this.indicatorEl();
41633 this.flag = this.flagEl();
41634 this.dialCodeHolder = this.dialCodeHolderEl();
41636 this.trigger = this.el.select('div.flag-box',true).first();
41637 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
41642 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41643 _this.list.setWidth(lw);
41646 this.list.on('mouseover', this.onViewOver, this);
41647 this.list.on('mousemove', this.onViewMove, this);
41648 this.inputEl().on("keyup", this.onKeyUp, this);
41649 this.inputEl().on("keypress", this.onKeyPress, this);
41651 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
41653 this.view = new Roo.View(this.list, this.tpl, {
41654 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41657 this.view.on('click', this.onViewClick, this);
41658 this.setValue(this.defaultDialCode);
41661 onTriggerClick : function(e)
41663 Roo.log('trigger click');
41668 if(this.isExpanded()){
41670 this.hasFocus = false;
41672 this.store.load({});
41673 this.hasFocus = true;
41678 isExpanded : function()
41680 return this.list.isVisible();
41683 collapse : function()
41685 if(!this.isExpanded()){
41689 Roo.get(document).un('mousedown', this.collapseIf, this);
41690 Roo.get(document).un('mousewheel', this.collapseIf, this);
41691 this.fireEvent('collapse', this);
41695 expand : function()
41699 if(this.isExpanded() || !this.hasFocus){
41703 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
41704 this.list.setWidth(lw);
41707 this.restrictHeight();
41709 Roo.get(document).on('mousedown', this.collapseIf, this);
41710 Roo.get(document).on('mousewheel', this.collapseIf, this);
41712 this.fireEvent('expand', this);
41715 restrictHeight : function()
41717 this.list.alignTo(this.inputEl(), this.listAlign);
41718 this.list.alignTo(this.inputEl(), this.listAlign);
41721 onViewOver : function(e, t)
41723 if(this.inKeyMode){
41726 var item = this.view.findItemFromChild(t);
41729 var index = this.view.indexOf(item);
41730 this.select(index, false);
41735 onViewClick : function(view, doFocus, el, e)
41737 var index = this.view.getSelectedIndexes()[0];
41739 var r = this.store.getAt(index);
41742 this.onSelect(r, index);
41744 if(doFocus !== false && !this.blockFocus){
41745 this.inputEl().focus();
41749 onViewMove : function(e, t)
41751 this.inKeyMode = false;
41754 select : function(index, scrollIntoView)
41756 this.selectedIndex = index;
41757 this.view.select(index);
41758 if(scrollIntoView !== false){
41759 var el = this.view.getNode(index);
41761 this.list.scrollChildIntoView(el, false);
41766 createList : function()
41768 this.list = Roo.get(document.body).createChild({
41770 cls: 'typeahead typeahead-long dropdown-menu tel-list',
41771 style: 'display:none'
41774 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
41777 collapseIf : function(e)
41779 var in_combo = e.within(this.el);
41780 var in_list = e.within(this.list);
41781 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
41783 if (in_combo || in_list || is_list) {
41789 onSelect : function(record, index)
41791 if(this.fireEvent('beforeselect', this, record, index) !== false){
41793 this.setFlagClass(record.data.iso2);
41794 this.setDialCode(record.data.dialCode);
41795 this.hasFocus = false;
41797 this.fireEvent('select', this, record, index);
41801 flagEl : function()
41803 var flag = this.el.select('div.flag',true).first();
41810 dialCodeHolderEl : function()
41812 var d = this.el.select('input.dial-code-holder',true).first();
41819 setDialCode : function(v)
41821 this.dialCodeHolder.dom.value = '+'+v;
41824 setFlagClass : function(n)
41826 this.flag.dom.className = 'flag '+n;
41829 getValue : function()
41831 var v = this.inputEl().getValue();
41832 if(this.dialCodeHolder) {
41833 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
41838 setValue : function(v)
41840 var d = this.getDialCode(v);
41842 //invalid dial code
41843 if(v.length == 0 || !d || d.length == 0) {
41845 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
41846 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41852 this.setFlagClass(this.dialCodeMapping[d].iso2);
41853 this.setDialCode(d);
41854 this.inputEl().dom.value = v.replace('+'+d,'');
41855 this.hiddenEl().dom.value = this.getValue();
41860 getDialCode : function(v)
41864 if (v.length == 0) {
41865 return this.dialCodeHolder.dom.value;
41869 if (v.charAt(0) != "+") {
41872 var numericChars = "";
41873 for (var i = 1; i < v.length; i++) {
41874 var c = v.charAt(i);
41877 if (this.dialCodeMapping[numericChars]) {
41878 dialCode = v.substr(1, i);
41880 if (numericChars.length == 4) {
41890 this.setValue(this.defaultDialCode);
41894 hiddenEl : function()
41896 return this.el.select('input.hidden-tel-input',true).first();
41899 // after setting val
41900 onKeyUp : function(e){
41901 this.setValue(this.getValue());
41904 onKeyPress : function(e){
41905 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
41912 * @class Roo.bootstrap.MoneyField
41913 * @extends Roo.bootstrap.ComboBox
41914 * Bootstrap MoneyField class
41917 * Create a new MoneyField.
41918 * @param {Object} config Configuration options
41921 Roo.bootstrap.MoneyField = function(config) {
41923 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
41927 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
41930 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
41932 allowDecimals : true,
41934 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
41936 decimalSeparator : ".",
41938 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
41940 decimalPrecision : 0,
41942 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
41944 allowNegative : true,
41946 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
41950 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
41952 minValue : Number.NEGATIVE_INFINITY,
41954 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
41956 maxValue : Number.MAX_VALUE,
41958 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
41960 minText : "The minimum value for this field is {0}",
41962 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
41964 maxText : "The maximum value for this field is {0}",
41966 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
41967 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
41969 nanText : "{0} is not a valid number",
41971 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
41975 * @cfg {String} defaults currency of the MoneyField
41976 * value should be in lkey
41978 defaultCurrency : false,
41980 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
41982 thousandsDelimiter : false,
41984 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
41995 getAutoCreate : function()
41997 var align = this.labelAlign || this.parentLabelAlign();
42009 cls : 'form-control roo-money-amount-input',
42010 autocomplete: 'new-password'
42013 var hiddenInput = {
42017 cls: 'hidden-number-input'
42020 if(this.max_length) {
42021 input.maxlength = this.max_length;
42025 hiddenInput.name = this.name;
42028 if (this.disabled) {
42029 input.disabled = true;
42032 var clg = 12 - this.inputlg;
42033 var cmd = 12 - this.inputmd;
42034 var csm = 12 - this.inputsm;
42035 var cxs = 12 - this.inputxs;
42039 cls : 'row roo-money-field',
42043 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
42047 cls: 'roo-select2-container input-group',
42051 cls : 'form-control roo-money-currency-input',
42052 autocomplete: 'new-password',
42054 name : this.currencyName
42058 cls : 'input-group-addon',
42072 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
42076 cls: this.hasFeedback ? 'has-feedback' : '',
42087 if (this.fieldLabel.length) {
42090 tooltip: 'This field is required'
42096 cls: 'control-label',
42102 html: this.fieldLabel
42105 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42111 if(this.indicatorpos == 'right') {
42112 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42119 if(align == 'left') {
42127 if(this.labelWidth > 12){
42128 label.style = "width: " + this.labelWidth + 'px';
42130 if(this.labelWidth < 13 && this.labelmd == 0){
42131 this.labelmd = this.labelWidth;
42133 if(this.labellg > 0){
42134 label.cls += ' col-lg-' + this.labellg;
42135 input.cls += ' col-lg-' + (12 - this.labellg);
42137 if(this.labelmd > 0){
42138 label.cls += ' col-md-' + this.labelmd;
42139 container.cls += ' col-md-' + (12 - this.labelmd);
42141 if(this.labelsm > 0){
42142 label.cls += ' col-sm-' + this.labelsm;
42143 container.cls += ' col-sm-' + (12 - this.labelsm);
42145 if(this.labelxs > 0){
42146 label.cls += ' col-xs-' + this.labelxs;
42147 container.cls += ' col-xs-' + (12 - this.labelxs);
42158 var settings = this;
42160 ['xs','sm','md','lg'].map(function(size){
42161 if (settings[size]) {
42162 cfg.cls += ' col-' + size + '-' + settings[size];
42169 initEvents : function()
42171 this.indicator = this.indicatorEl();
42173 this.initCurrencyEvent();
42175 this.initNumberEvent();
42178 initCurrencyEvent : function()
42181 throw "can not find store for combo";
42184 this.store = Roo.factory(this.store, Roo.data);
42185 this.store.parent = this;
42189 this.triggerEl = this.el.select('.input-group-addon', true).first();
42191 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
42196 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42197 _this.list.setWidth(lw);
42200 this.list.on('mouseover', this.onViewOver, this);
42201 this.list.on('mousemove', this.onViewMove, this);
42202 this.list.on('scroll', this.onViewScroll, this);
42205 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
42208 this.view = new Roo.View(this.list, this.tpl, {
42209 singleSelect:true, store: this.store, selectedClass: this.selectedClass
42212 this.view.on('click', this.onViewClick, this);
42214 this.store.on('beforeload', this.onBeforeLoad, this);
42215 this.store.on('load', this.onLoad, this);
42216 this.store.on('loadexception', this.onLoadException, this);
42218 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
42219 "up" : function(e){
42220 this.inKeyMode = true;
42224 "down" : function(e){
42225 if(!this.isExpanded()){
42226 this.onTriggerClick();
42228 this.inKeyMode = true;
42233 "enter" : function(e){
42236 if(this.fireEvent("specialkey", this, e)){
42237 this.onViewClick(false);
42243 "esc" : function(e){
42247 "tab" : function(e){
42250 if(this.fireEvent("specialkey", this, e)){
42251 this.onViewClick(false);
42259 doRelay : function(foo, bar, hname){
42260 if(hname == 'down' || this.scope.isExpanded()){
42261 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
42269 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
42273 initNumberEvent : function(e)
42275 this.inputEl().on("keydown" , this.fireKey, this);
42276 this.inputEl().on("focus", this.onFocus, this);
42277 this.inputEl().on("blur", this.onBlur, this);
42279 this.inputEl().relayEvent('keyup', this);
42281 if(this.indicator){
42282 this.indicator.addClass('invisible');
42285 this.originalValue = this.getValue();
42287 if(this.validationEvent == 'keyup'){
42288 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
42289 this.inputEl().on('keyup', this.filterValidation, this);
42291 else if(this.validationEvent !== false){
42292 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
42295 if(this.selectOnFocus){
42296 this.on("focus", this.preFocus, this);
42299 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
42300 this.inputEl().on("keypress", this.filterKeys, this);
42302 this.inputEl().relayEvent('keypress', this);
42305 var allowed = "0123456789";
42307 if(this.allowDecimals){
42308 allowed += this.decimalSeparator;
42311 if(this.allowNegative){
42315 if(this.thousandsDelimiter) {
42319 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
42321 var keyPress = function(e){
42323 var k = e.getKey();
42325 var c = e.getCharCode();
42328 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
42329 allowed.indexOf(String.fromCharCode(c)) === -1
42335 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
42339 if(allowed.indexOf(String.fromCharCode(c)) === -1){
42344 this.inputEl().on("keypress", keyPress, this);
42348 onTriggerClick : function(e)
42355 this.loadNext = false;
42357 if(this.isExpanded()){
42362 this.hasFocus = true;
42364 if(this.triggerAction == 'all') {
42365 this.doQuery(this.allQuery, true);
42369 this.doQuery(this.getRawValue());
42372 getCurrency : function()
42374 var v = this.currencyEl().getValue();
42379 restrictHeight : function()
42381 this.list.alignTo(this.currencyEl(), this.listAlign);
42382 this.list.alignTo(this.currencyEl(), this.listAlign);
42385 onViewClick : function(view, doFocus, el, e)
42387 var index = this.view.getSelectedIndexes()[0];
42389 var r = this.store.getAt(index);
42392 this.onSelect(r, index);
42396 onSelect : function(record, index){
42398 if(this.fireEvent('beforeselect', this, record, index) !== false){
42400 this.setFromCurrencyData(index > -1 ? record.data : false);
42404 this.fireEvent('select', this, record, index);
42408 setFromCurrencyData : function(o)
42412 this.lastCurrency = o;
42414 if (this.currencyField) {
42415 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
42417 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
42420 this.lastSelectionText = currency;
42422 //setting default currency
42423 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
42424 this.setCurrency(this.defaultCurrency);
42428 this.setCurrency(currency);
42431 setFromData : function(o)
42435 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
42437 this.setFromCurrencyData(c);
42442 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
42444 Roo.log('no value set for '+ (this.name ? this.name : this.id));
42447 this.setValue(value);
42451 setCurrency : function(v)
42453 this.currencyValue = v;
42456 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
42461 setValue : function(v)
42463 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
42469 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
42471 this.inputEl().dom.value = (v == '') ? '' :
42472 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
42474 if(!this.allowZero && v === '0') {
42475 this.hiddenEl().dom.value = '';
42476 this.inputEl().dom.value = '';
42483 getRawValue : function()
42485 var v = this.inputEl().getValue();
42490 getValue : function()
42492 return this.fixPrecision(this.parseValue(this.getRawValue()));
42495 parseValue : function(value)
42497 if(this.thousandsDelimiter) {
42499 r = new RegExp(",", "g");
42500 value = value.replace(r, "");
42503 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
42504 return isNaN(value) ? '' : value;
42508 fixPrecision : function(value)
42510 if(this.thousandsDelimiter) {
42512 r = new RegExp(",", "g");
42513 value = value.replace(r, "");
42516 var nan = isNaN(value);
42518 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
42519 return nan ? '' : value;
42521 return parseFloat(value).toFixed(this.decimalPrecision);
42524 decimalPrecisionFcn : function(v)
42526 return Math.floor(v);
42529 validateValue : function(value)
42531 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
42535 var num = this.parseValue(value);
42538 this.markInvalid(String.format(this.nanText, value));
42542 if(num < this.minValue){
42543 this.markInvalid(String.format(this.minText, this.minValue));
42547 if(num > this.maxValue){
42548 this.markInvalid(String.format(this.maxText, this.maxValue));
42555 validate : function()
42557 if(this.disabled || this.allowBlank){
42562 var currency = this.getCurrency();
42564 if(this.validateValue(this.getRawValue()) && currency.length){
42569 this.markInvalid();
42573 getName: function()
42578 beforeBlur : function()
42584 var v = this.parseValue(this.getRawValue());
42591 onBlur : function()
42595 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
42596 //this.el.removeClass(this.focusClass);
42599 this.hasFocus = false;
42601 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
42605 var v = this.getValue();
42607 if(String(v) !== String(this.startValue)){
42608 this.fireEvent('change', this, v, this.startValue);
42611 this.fireEvent("blur", this);
42614 inputEl : function()
42616 return this.el.select('.roo-money-amount-input', true).first();
42619 currencyEl : function()
42621 return this.el.select('.roo-money-currency-input', true).first();
42624 hiddenEl : function()
42626 return this.el.select('input.hidden-number-input',true).first();
42630 * @class Roo.bootstrap.BezierSignature
42631 * @extends Roo.bootstrap.Component
42632 * Bootstrap BezierSignature class
42633 * This script refer to:
42634 * Title: Signature Pad
42636 * Availability: https://github.com/szimek/signature_pad
42639 * Create a new BezierSignature
42640 * @param {Object} config The config object
42643 Roo.bootstrap.BezierSignature = function(config){
42644 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
42650 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
42657 mouse_btn_down: true,
42660 * @cfg {int} canvas height
42662 canvas_height: '200px',
42665 * @cfg {float|function} Radius of a single dot.
42670 * @cfg {float} Minimum width of a line. Defaults to 0.5.
42675 * @cfg {float} Maximum width of a line. Defaults to 2.5.
42680 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
42685 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
42690 * @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.
42692 bg_color: 'rgba(0, 0, 0, 0)',
42695 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
42697 dot_color: 'black',
42700 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
42702 velocity_filter_weight: 0.7,
42705 * @cfg {function} Callback when stroke begin.
42710 * @cfg {function} Callback when stroke end.
42714 getAutoCreate : function()
42716 var cls = 'roo-signature column';
42719 cls += ' ' + this.cls;
42729 for(var i = 0; i < col_sizes.length; i++) {
42730 if(this[col_sizes[i]]) {
42731 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
42741 cls: 'roo-signature-body',
42745 cls: 'roo-signature-body-canvas',
42746 height: this.canvas_height,
42747 width: this.canvas_width
42754 style: 'display: none'
42762 initEvents: function()
42764 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
42766 var canvas = this.canvasEl();
42768 // mouse && touch event swapping...
42769 canvas.dom.style.touchAction = 'none';
42770 canvas.dom.style.msTouchAction = 'none';
42772 this.mouse_btn_down = false;
42773 canvas.on('mousedown', this._handleMouseDown, this);
42774 canvas.on('mousemove', this._handleMouseMove, this);
42775 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
42777 if (window.PointerEvent) {
42778 canvas.on('pointerdown', this._handleMouseDown, this);
42779 canvas.on('pointermove', this._handleMouseMove, this);
42780 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
42783 if ('ontouchstart' in window) {
42784 canvas.on('touchstart', this._handleTouchStart, this);
42785 canvas.on('touchmove', this._handleTouchMove, this);
42786 canvas.on('touchend', this._handleTouchEnd, this);
42789 Roo.EventManager.onWindowResize(this.resize, this, true);
42791 // file input event
42792 this.fileEl().on('change', this.uploadImage, this);
42799 resize: function(){
42801 var canvas = this.canvasEl().dom;
42802 var ctx = this.canvasElCtx();
42803 var img_data = false;
42805 if(canvas.width > 0) {
42806 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
42808 // setting canvas width will clean img data
42811 var style = window.getComputedStyle ?
42812 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
42814 var padding_left = parseInt(style.paddingLeft) || 0;
42815 var padding_right = parseInt(style.paddingRight) || 0;
42817 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
42820 ctx.putImageData(img_data, 0, 0);
42824 _handleMouseDown: function(e)
42826 if (e.browserEvent.which === 1) {
42827 this.mouse_btn_down = true;
42828 this.strokeBegin(e);
42832 _handleMouseMove: function (e)
42834 if (this.mouse_btn_down) {
42835 this.strokeMoveUpdate(e);
42839 _handleMouseUp: function (e)
42841 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
42842 this.mouse_btn_down = false;
42847 _handleTouchStart: function (e) {
42849 e.preventDefault();
42850 if (e.browserEvent.targetTouches.length === 1) {
42851 // var touch = e.browserEvent.changedTouches[0];
42852 // this.strokeBegin(touch);
42854 this.strokeBegin(e); // assume e catching the correct xy...
42858 _handleTouchMove: function (e) {
42859 e.preventDefault();
42860 // var touch = event.targetTouches[0];
42861 // _this._strokeMoveUpdate(touch);
42862 this.strokeMoveUpdate(e);
42865 _handleTouchEnd: function (e) {
42866 var wasCanvasTouched = e.target === this.canvasEl().dom;
42867 if (wasCanvasTouched) {
42868 e.preventDefault();
42869 // var touch = event.changedTouches[0];
42870 // _this._strokeEnd(touch);
42875 reset: function () {
42876 this._lastPoints = [];
42877 this._lastVelocity = 0;
42878 this._lastWidth = (this.min_width + this.max_width) / 2;
42879 this.canvasElCtx().fillStyle = this.dot_color;
42882 strokeMoveUpdate: function(e)
42884 this.strokeUpdate(e);
42886 if (this.throttle) {
42887 this.throttleStroke(this.strokeUpdate, this.throttle);
42890 this.strokeUpdate(e);
42894 strokeBegin: function(e)
42896 var newPointGroup = {
42897 color: this.dot_color,
42901 if (typeof this.onBegin === 'function') {
42905 this.curve_data.push(newPointGroup);
42907 this.strokeUpdate(e);
42910 strokeUpdate: function(e)
42912 var rect = this.canvasEl().dom.getBoundingClientRect();
42913 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
42914 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
42915 var lastPoints = lastPointGroup.points;
42916 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
42917 var isLastPointTooClose = lastPoint
42918 ? point.distanceTo(lastPoint) <= this.min_distance
42920 var color = lastPointGroup.color;
42921 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
42922 var curve = this.addPoint(point);
42924 this.drawDot({color: color, point: point});
42927 this.drawCurve({color: color, curve: curve});
42937 strokeEnd: function(e)
42939 this.strokeUpdate(e);
42940 if (typeof this.onEnd === 'function') {
42945 addPoint: function (point) {
42946 var _lastPoints = this._lastPoints;
42947 _lastPoints.push(point);
42948 if (_lastPoints.length > 2) {
42949 if (_lastPoints.length === 3) {
42950 _lastPoints.unshift(_lastPoints[0]);
42952 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
42953 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
42954 _lastPoints.shift();
42960 calculateCurveWidths: function (startPoint, endPoint) {
42961 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
42962 (1 - this.velocity_filter_weight) * this._lastVelocity;
42964 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
42967 start: this._lastWidth
42970 this._lastVelocity = velocity;
42971 this._lastWidth = newWidth;
42975 drawDot: function (_a) {
42976 var color = _a.color, point = _a.point;
42977 var ctx = this.canvasElCtx();
42978 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
42980 this.drawCurveSegment(point.x, point.y, width);
42982 ctx.fillStyle = color;
42986 drawCurve: function (_a) {
42987 var color = _a.color, curve = _a.curve;
42988 var ctx = this.canvasElCtx();
42989 var widthDelta = curve.endWidth - curve.startWidth;
42990 var drawSteps = Math.floor(curve.length()) * 2;
42992 ctx.fillStyle = color;
42993 for (var i = 0; i < drawSteps; i += 1) {
42994 var t = i / drawSteps;
43000 var x = uuu * curve.startPoint.x;
43001 x += 3 * uu * t * curve.control1.x;
43002 x += 3 * u * tt * curve.control2.x;
43003 x += ttt * curve.endPoint.x;
43004 var y = uuu * curve.startPoint.y;
43005 y += 3 * uu * t * curve.control1.y;
43006 y += 3 * u * tt * curve.control2.y;
43007 y += ttt * curve.endPoint.y;
43008 var width = curve.startWidth + ttt * widthDelta;
43009 this.drawCurveSegment(x, y, width);
43015 drawCurveSegment: function (x, y, width) {
43016 var ctx = this.canvasElCtx();
43018 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
43019 this.is_empty = false;
43024 var ctx = this.canvasElCtx();
43025 var canvas = this.canvasEl().dom;
43026 ctx.fillStyle = this.bg_color;
43027 ctx.clearRect(0, 0, canvas.width, canvas.height);
43028 ctx.fillRect(0, 0, canvas.width, canvas.height);
43029 this.curve_data = [];
43031 this.is_empty = true;
43036 return this.el.select('input',true).first();
43039 canvasEl: function()
43041 return this.el.select('canvas',true).first();
43044 canvasElCtx: function()
43046 return this.el.select('canvas',true).first().dom.getContext('2d');
43049 getImage: function(type)
43051 if(this.is_empty) {
43056 return this.canvasEl().dom.toDataURL('image/'+type, 1);
43059 drawFromImage: function(img_src)
43061 var img = new Image();
43063 img.onload = function(){
43064 this.canvasElCtx().drawImage(img, 0, 0);
43069 this.is_empty = false;
43072 selectImage: function()
43074 this.fileEl().dom.click();
43077 uploadImage: function(e)
43079 var reader = new FileReader();
43081 reader.onload = function(e){
43082 var img = new Image();
43083 img.onload = function(){
43085 this.canvasElCtx().drawImage(img, 0, 0);
43087 img.src = e.target.result;
43090 reader.readAsDataURL(e.target.files[0]);
43093 // Bezier Point Constructor
43094 Point: (function () {
43095 function Point(x, y, time) {
43098 this.time = time || Date.now();
43100 Point.prototype.distanceTo = function (start) {
43101 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
43103 Point.prototype.equals = function (other) {
43104 return this.x === other.x && this.y === other.y && this.time === other.time;
43106 Point.prototype.velocityFrom = function (start) {
43107 return this.time !== start.time
43108 ? this.distanceTo(start) / (this.time - start.time)
43115 // Bezier Constructor
43116 Bezier: (function () {
43117 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
43118 this.startPoint = startPoint;
43119 this.control2 = control2;
43120 this.control1 = control1;
43121 this.endPoint = endPoint;
43122 this.startWidth = startWidth;
43123 this.endWidth = endWidth;
43125 Bezier.fromPoints = function (points, widths, scope) {
43126 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
43127 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
43128 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
43130 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
43131 var dx1 = s1.x - s2.x;
43132 var dy1 = s1.y - s2.y;
43133 var dx2 = s2.x - s3.x;
43134 var dy2 = s2.y - s3.y;
43135 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
43136 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
43137 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
43138 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
43139 var dxm = m1.x - m2.x;
43140 var dym = m1.y - m2.y;
43141 var k = l2 / (l1 + l2);
43142 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
43143 var tx = s2.x - cm.x;
43144 var ty = s2.y - cm.y;
43146 c1: new scope.Point(m1.x + tx, m1.y + ty),
43147 c2: new scope.Point(m2.x + tx, m2.y + ty)
43150 Bezier.prototype.length = function () {
43155 for (var i = 0; i <= steps; i += 1) {
43157 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
43158 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
43160 var xdiff = cx - px;
43161 var ydiff = cy - py;
43162 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
43169 Bezier.prototype.point = function (t, start, c1, c2, end) {
43170 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
43171 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
43172 + (3.0 * c2 * (1.0 - t) * t * t)
43173 + (end * t * t * t);
43178 throttleStroke: function(fn, wait) {
43179 if (wait === void 0) { wait = 250; }
43181 var timeout = null;
43185 var later = function () {
43186 previous = Date.now();
43188 result = fn.apply(storedContext, storedArgs);
43190 storedContext = null;
43194 return function wrapper() {
43196 for (var _i = 0; _i < arguments.length; _i++) {
43197 args[_i] = arguments[_i];
43199 var now = Date.now();
43200 var remaining = wait - (now - previous);
43201 storedContext = this;
43203 if (remaining <= 0 || remaining > wait) {
43205 clearTimeout(timeout);
43209 result = fn.apply(storedContext, storedArgs);
43211 storedContext = null;
43215 else if (!timeout) {
43216 timeout = window.setTimeout(later, remaining);