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 cards.push(this.items[i]);
2285 if (ctarget < 0 && pos == 'above') {
2286 ctarget = i > 0 ? i - 1 : 0;
2287 cpos = i > 0 ? 'below' : pos;
2290 if (!cards.length) {
2291 return [ true, 'below' ];
2295 ctarget = cards.length -1;
2298 if (cards[ctarget].el == dragged_card_el) {
2302 if (cpos == 'below') {
2303 var card_after = ctarget+1 == cards.length ? false : cards[ctarget+1];
2305 // then above should not be dragged_card_el.
2308 if (card_after && card_after.el == dragged_card_el) {
2311 return [ cards[ctarget], cpos ];
2315 var card_before = ctarget > 0 ? cards[ctarget-1] : false;
2318 if (card_before && card_before.el == dragged_card_el) {
2322 return [ cards[ctarget], cpos, cards, ctarget ];
2325 onNodeEnter : function(n, dd, e, data){
2328 onNodeOver : function(n, dd, e, data)
2331 var target_info = this.getTargetFromEvent(e,data.source.el);
2332 if (target_info === false) {
2333 this.dropPlaceHolder('hide');
2336 Roo.log(['getTargetFromEvent', target_info[0].el.dom.id,target_info[1]]);
2339 this.dropPlaceHolder('show', target_info,data);
2343 onNodeOut : function(n, dd, e, data){
2344 this.dropPlaceHolder('hide');
2347 onNodeDrop : function(n, dd, e, data)
2350 // call drop - return false if
2351 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
2355 var target_info = this.getTargetFromEvent(e,data.source.el);
2356 if (target_info === false) {
2360 var pt = this.getDropPoint(e, n, dd);
2361 var insertAt = (n == this.bodyEl.dom) ? this.items.length : n.nodeIndex;
2362 if (pt == "below") {
2365 for (var i = 0; i < this.items.length; i++) {
2366 var r = this.items[i];
2367 //var dup = this.store.getById(r.id);
2368 if (dup && (dd != this.dragZone)) {
2369 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
2372 this.store.insert(insertAt++, r.copy());
2374 data.source.isDirtyFlag = true;
2376 this.store.insert(insertAt++, r);
2378 this.isDirtyFlag = true;
2381 this.dragZone.cachedTarget = null;
2385 /** Decide whether to drop above or below a View node. */
2386 getDropPoint : function(e, n, dd)
2391 if (n == this.bodyEl.dom) {
2394 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
2395 var c = t + (b - t) / 2;
2396 var y = Roo.lib.Event.getPageY(e);
2403 onToggleCollapse : function(e)
2405 if (this.collapsed) {
2406 this.el.select('.roo-collapse-toggle').removeClass('collapsed');
2407 this.el.select('.roo-collapsable').addClass('show');
2408 this.collapsed = false;
2411 this.el.select('.roo-collapse-toggle').addClass('collapsed');
2412 this.el.select('.roo-collapsable').removeClass('show');
2413 this.collapsed = true;
2417 dropPlaceHolder: function (action, where_ar, data)
2419 if (this.dropEl === false) {
2420 this.dropEl = Roo.DomHelper.append(this.bodyEl, {
2424 this.dropEl.removeClass(['d-none', 'd-block']);
2425 if (action == 'hide') {
2427 this.dropEl.addClass('d-none');
2430 var cardel = where_ar[0].el.dom;
2432 this.dropEl.dom.parentNode.removeChild(this.dropEl.dom);
2433 if (where_ar[1] == 'above') {
2434 cardel.parentNode.insertBefore(this.dropEl.dom, cardel);
2435 } else if (cardel.nextSibling) {
2436 cardel.parentNode.insertBefore(this.dropEl.dom,cardel.nextSibling);
2438 cardel.parentNode.append(this.dropEl.dom);
2440 this.dropEl.addClass('d-block roo-card-dropzone');
2442 this.dropEl.setHeight( Roo.get(data.ddel).getHeight() );
2456 * Card header - holder for the card header elements.
2461 * @class Roo.bootstrap.CardHeader
2462 * @extends Roo.bootstrap.Element
2463 * Bootstrap CardHeader class
2465 * Create a new Card Header - that you can embed children into
2466 * @param {Object} config The config object
2469 Roo.bootstrap.CardHeader = function(config){
2470 Roo.bootstrap.CardHeader.superclass.constructor.call(this, config);
2473 Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element, {
2476 container_method : 'getCardHeader'
2489 * Card header - holder for the card header elements.
2494 * @class Roo.bootstrap.CardImageTop
2495 * @extends Roo.bootstrap.Element
2496 * Bootstrap CardImageTop class
2498 * Create a new Card Image Top container
2499 * @param {Object} config The config object
2502 Roo.bootstrap.CardImageTop = function(config){
2503 Roo.bootstrap.CardImageTop.superclass.constructor.call(this, config);
2506 Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element, {
2509 container_method : 'getCardImageTop'
2527 * @class Roo.bootstrap.Img
2528 * @extends Roo.bootstrap.Component
2529 * Bootstrap Img class
2530 * @cfg {Boolean} imgResponsive false | true
2531 * @cfg {String} border rounded | circle | thumbnail
2532 * @cfg {String} src image source
2533 * @cfg {String} alt image alternative text
2534 * @cfg {String} href a tag href
2535 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
2536 * @cfg {String} xsUrl xs image source
2537 * @cfg {String} smUrl sm image source
2538 * @cfg {String} mdUrl md image source
2539 * @cfg {String} lgUrl lg image source
2542 * Create a new Input
2543 * @param {Object} config The config object
2546 Roo.bootstrap.Img = function(config){
2547 Roo.bootstrap.Img.superclass.constructor.call(this, config);
2553 * The img click event for the img.
2554 * @param {Roo.EventObject} e
2560 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
2562 imgResponsive: true,
2572 getAutoCreate : function()
2574 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2575 return this.createSingleImg();
2580 cls: 'roo-image-responsive-group',
2585 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
2587 if(!_this[size + 'Url']){
2593 cls: (_this.imgResponsive) ? 'img-responsive' : '',
2594 html: _this.html || cfg.html,
2595 src: _this[size + 'Url']
2598 img.cls += ' roo-image-responsive-' + size;
2600 var s = ['xs', 'sm', 'md', 'lg'];
2602 s.splice(s.indexOf(size), 1);
2604 Roo.each(s, function(ss){
2605 img.cls += ' hidden-' + ss;
2608 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
2609 cfg.cls += ' img-' + _this.border;
2613 cfg.alt = _this.alt;
2626 a.target = _this.target;
2630 cfg.cn.push((_this.href) ? a : img);
2637 createSingleImg : function()
2641 cls: (this.imgResponsive) ? 'img-responsive' : '',
2643 src : 'about:blank' // just incase src get's set to undefined?!?
2646 cfg.html = this.html || cfg.html;
2648 cfg.src = this.src || cfg.src;
2650 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
2651 cfg.cls += ' img-' + this.border;
2668 a.target = this.target;
2673 return (this.href) ? a : cfg;
2676 initEvents: function()
2679 this.el.on('click', this.onClick, this);
2684 onClick : function(e)
2686 Roo.log('img onclick');
2687 this.fireEvent('click', this, e);
2690 * Sets the url of the image - used to update it
2691 * @param {String} url the url of the image
2694 setSrc : function(url)
2698 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2699 this.el.dom.src = url;
2703 this.el.select('img', true).first().dom.src = url;
2719 * @class Roo.bootstrap.Link
2720 * @extends Roo.bootstrap.Component
2721 * Bootstrap Link Class
2722 * @cfg {String} alt image alternative text
2723 * @cfg {String} href a tag href
2724 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
2725 * @cfg {String} html the content of the link.
2726 * @cfg {String} anchor name for the anchor link
2727 * @cfg {String} fa - favicon
2729 * @cfg {Boolean} preventDefault (true | false) default false
2733 * Create a new Input
2734 * @param {Object} config The config object
2737 Roo.bootstrap.Link = function(config){
2738 Roo.bootstrap.Link.superclass.constructor.call(this, config);
2744 * The img click event for the img.
2745 * @param {Roo.EventObject} e
2751 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
2755 preventDefault: false,
2761 getAutoCreate : function()
2763 var html = this.html || '';
2765 if (this.fa !== false) {
2766 html = '<i class="fa fa-' + this.fa + '"></i>';
2771 // anchor's do not require html/href...
2772 if (this.anchor === false) {
2774 cfg.href = this.href || '#';
2776 cfg.name = this.anchor;
2777 if (this.html !== false || this.fa !== false) {
2780 if (this.href !== false) {
2781 cfg.href = this.href;
2785 if(this.alt !== false){
2790 if(this.target !== false) {
2791 cfg.target = this.target;
2797 initEvents: function() {
2799 if(!this.href || this.preventDefault){
2800 this.el.on('click', this.onClick, this);
2804 onClick : function(e)
2806 if(this.preventDefault){
2809 //Roo.log('img onclick');
2810 this.fireEvent('click', this, e);
2823 * @class Roo.bootstrap.Header
2824 * @extends Roo.bootstrap.Component
2825 * Bootstrap Header class
2826 * @cfg {String} html content of header
2827 * @cfg {Number} level (1|2|3|4|5|6) default 1
2830 * Create a new Header
2831 * @param {Object} config The config object
2835 Roo.bootstrap.Header = function(config){
2836 Roo.bootstrap.Header.superclass.constructor.call(this, config);
2839 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
2847 getAutoCreate : function(){
2852 tag: 'h' + (1 *this.level),
2853 html: this.html || ''
2865 * Ext JS Library 1.1.1
2866 * Copyright(c) 2006-2007, Ext JS, LLC.
2868 * Originally Released Under LGPL - original licence link has changed is not relivant.
2871 * <script type="text/javascript">
2875 * @class Roo.bootstrap.MenuMgr
2876 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
2879 Roo.bootstrap.MenuMgr = function(){
2880 var menus, active, groups = {}, attached = false, lastShow = new Date();
2882 // private - called when first menu is created
2885 active = new Roo.util.MixedCollection();
2886 Roo.get(document).addKeyListener(27, function(){
2887 if(active.length > 0){
2895 if(active && active.length > 0){
2896 var c = active.clone();
2906 if(active.length < 1){
2907 Roo.get(document).un("mouseup", onMouseDown);
2915 var last = active.last();
2916 lastShow = new Date();
2919 Roo.get(document).on("mouseup", onMouseDown);
2924 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
2925 m.parentMenu.activeChild = m;
2926 }else if(last && last.isVisible()){
2927 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
2932 function onBeforeHide(m){
2934 m.activeChild.hide();
2936 if(m.autoHideTimer){
2937 clearTimeout(m.autoHideTimer);
2938 delete m.autoHideTimer;
2943 function onBeforeShow(m){
2944 var pm = m.parentMenu;
2945 if(!pm && !m.allowOtherMenus){
2947 }else if(pm && pm.activeChild && active != m){
2948 pm.activeChild.hide();
2952 // private this should really trigger on mouseup..
2953 function onMouseDown(e){
2954 Roo.log("on Mouse Up");
2956 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
2957 Roo.log("MenuManager hideAll");
2966 function onBeforeCheck(mi, state){
2968 var g = groups[mi.group];
2969 for(var i = 0, l = g.length; i < l; i++){
2971 g[i].setChecked(false);
2980 * Hides all menus that are currently visible
2982 hideAll : function(){
2987 register : function(menu){
2991 menus[menu.id] = menu;
2992 menu.on("beforehide", onBeforeHide);
2993 menu.on("hide", onHide);
2994 menu.on("beforeshow", onBeforeShow);
2995 menu.on("show", onShow);
2997 if(g && menu.events["checkchange"]){
3001 groups[g].push(menu);
3002 menu.on("checkchange", onCheck);
3007 * Returns a {@link Roo.menu.Menu} object
3008 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
3009 * be used to generate and return a new Menu instance.
3011 get : function(menu){
3012 if(typeof menu == "string"){ // menu id
3014 }else if(menu.events){ // menu instance
3017 /*else if(typeof menu.length == 'number'){ // array of menu items?
3018 return new Roo.bootstrap.Menu({items:menu});
3019 }else{ // otherwise, must be a config
3020 return new Roo.bootstrap.Menu(menu);
3027 unregister : function(menu){
3028 delete menus[menu.id];
3029 menu.un("beforehide", onBeforeHide);
3030 menu.un("hide", onHide);
3031 menu.un("beforeshow", onBeforeShow);
3032 menu.un("show", onShow);
3034 if(g && menu.events["checkchange"]){
3035 groups[g].remove(menu);
3036 menu.un("checkchange", onCheck);
3041 registerCheckable : function(menuItem){
3042 var g = menuItem.group;
3047 groups[g].push(menuItem);
3048 menuItem.on("beforecheckchange", onBeforeCheck);
3053 unregisterCheckable : function(menuItem){
3054 var g = menuItem.group;
3056 groups[g].remove(menuItem);
3057 menuItem.un("beforecheckchange", onBeforeCheck);
3069 * @class Roo.bootstrap.Menu
3070 * @extends Roo.bootstrap.Component
3071 * Bootstrap Menu class - container for MenuItems
3072 * @cfg {String} type (dropdown|treeview|submenu) type of menu
3073 * @cfg {bool} hidden if the menu should be hidden when rendered.
3074 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
3075 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
3079 * @param {Object} config The config object
3083 Roo.bootstrap.Menu = function(config){
3084 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
3085 if (this.registerMenu && this.type != 'treeview') {
3086 Roo.bootstrap.MenuMgr.register(this);
3093 * Fires before this menu is displayed (return false to block)
3094 * @param {Roo.menu.Menu} this
3099 * Fires before this menu is hidden (return false to block)
3100 * @param {Roo.menu.Menu} this
3105 * Fires after this menu is displayed
3106 * @param {Roo.menu.Menu} this
3111 * Fires after this menu is hidden
3112 * @param {Roo.menu.Menu} this
3117 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
3118 * @param {Roo.menu.Menu} this
3119 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3120 * @param {Roo.EventObject} e
3125 * Fires when the mouse is hovering over this menu
3126 * @param {Roo.menu.Menu} this
3127 * @param {Roo.EventObject} e
3128 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3133 * Fires when the mouse exits this menu
3134 * @param {Roo.menu.Menu} this
3135 * @param {Roo.EventObject} e
3136 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3141 * Fires when a menu item contained in this menu is clicked
3142 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
3143 * @param {Roo.EventObject} e
3147 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
3150 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
3154 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
3157 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
3159 registerMenu : true,
3161 menuItems :false, // stores the menu items..
3171 getChildContainer : function() {
3175 getAutoCreate : function(){
3177 //if (['right'].indexOf(this.align)!==-1) {
3178 // cfg.cn[1].cls += ' pull-right'
3184 cls : 'dropdown-menu' ,
3185 style : 'z-index:1000'
3189 if (this.type === 'submenu') {
3190 cfg.cls = 'submenu active';
3192 if (this.type === 'treeview') {
3193 cfg.cls = 'treeview-menu';
3198 initEvents : function() {
3200 // Roo.log("ADD event");
3201 // Roo.log(this.triggerEl.dom);
3203 this.triggerEl.on('click', this.onTriggerClick, this);
3205 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
3208 if (this.triggerEl.hasClass('nav-item')) {
3209 // dropdown toggle on the 'a' in BS4?
3210 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
3212 this.triggerEl.addClass('dropdown-toggle');
3215 this.el.on('touchstart' , this.onTouch, this);
3217 this.el.on('click' , this.onClick, this);
3219 this.el.on("mouseover", this.onMouseOver, this);
3220 this.el.on("mouseout", this.onMouseOut, this);
3224 findTargetItem : function(e)
3226 var t = e.getTarget(".dropdown-menu-item", this.el, true);
3230 //Roo.log(t); Roo.log(t.id);
3232 //Roo.log(this.menuitems);
3233 return this.menuitems.get(t.id);
3235 //return this.items.get(t.menuItemId);
3241 onTouch : function(e)
3243 Roo.log("menu.onTouch");
3244 //e.stopEvent(); this make the user popdown broken
3248 onClick : function(e)
3250 Roo.log("menu.onClick");
3252 var t = this.findTargetItem(e);
3253 if(!t || t.isContainer){
3258 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
3259 if(t == this.activeItem && t.shouldDeactivate(e)){
3260 this.activeItem.deactivate();
3261 delete this.activeItem;
3265 this.setActiveItem(t, true);
3273 Roo.log('pass click event');
3277 this.fireEvent("click", this, t, e);
3281 if(!t.href.length || t.href == '#'){
3282 (function() { _this.hide(); }).defer(100);
3287 onMouseOver : function(e){
3288 var t = this.findTargetItem(e);
3291 // if(t.canActivate && !t.disabled){
3292 // this.setActiveItem(t, true);
3296 this.fireEvent("mouseover", this, e, t);
3298 isVisible : function(){
3299 return !this.hidden;
3301 onMouseOut : function(e){
3302 var t = this.findTargetItem(e);
3305 // if(t == this.activeItem && t.shouldDeactivate(e)){
3306 // this.activeItem.deactivate();
3307 // delete this.activeItem;
3310 this.fireEvent("mouseout", this, e, t);
3315 * Displays this menu relative to another element
3316 * @param {String/HTMLElement/Roo.Element} element The element to align to
3317 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
3318 * the element (defaults to this.defaultAlign)
3319 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3321 show : function(el, pos, parentMenu)
3323 if (false === this.fireEvent("beforeshow", this)) {
3324 Roo.log("show canceled");
3327 this.parentMenu = parentMenu;
3332 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
3335 * Displays this menu at a specific xy position
3336 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
3337 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3339 showAt : function(xy, parentMenu, /* private: */_e){
3340 this.parentMenu = parentMenu;
3345 this.fireEvent("beforeshow", this);
3346 //xy = this.el.adjustForConstraints(xy);
3350 this.hideMenuItems();
3351 this.hidden = false;
3352 this.triggerEl.addClass('open');
3353 this.el.addClass('show');
3355 // reassign x when hitting right
3356 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
3357 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
3360 // reassign y when hitting bottom
3361 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
3362 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
3365 // but the list may align on trigger left or trigger top... should it be a properity?
3367 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
3372 this.fireEvent("show", this);
3378 this.doFocus.defer(50, this);
3382 doFocus : function(){
3384 this.focusEl.focus();
3389 * Hides this menu and optionally all parent menus
3390 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
3392 hide : function(deep)
3394 if (false === this.fireEvent("beforehide", this)) {
3395 Roo.log("hide canceled");
3398 this.hideMenuItems();
3399 if(this.el && this.isVisible()){
3401 if(this.activeItem){
3402 this.activeItem.deactivate();
3403 this.activeItem = null;
3405 this.triggerEl.removeClass('open');;
3406 this.el.removeClass('show');
3408 this.fireEvent("hide", this);
3410 if(deep === true && this.parentMenu){
3411 this.parentMenu.hide(true);
3415 onTriggerClick : function(e)
3417 Roo.log('trigger click');
3419 var target = e.getTarget();
3421 Roo.log(target.nodeName.toLowerCase());
3423 if(target.nodeName.toLowerCase() === 'i'){
3429 onTriggerPress : function(e)
3431 Roo.log('trigger press');
3432 //Roo.log(e.getTarget());
3433 // Roo.log(this.triggerEl.dom);
3435 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
3436 var pel = Roo.get(e.getTarget());
3437 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
3438 Roo.log('is treeview or dropdown?');
3442 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
3446 if (this.isVisible()) {
3451 this.show(this.triggerEl, '?', false);
3454 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
3461 hideMenuItems : function()
3463 Roo.log("hide Menu Items");
3468 this.el.select('.open',true).each(function(aa) {
3470 aa.removeClass('open');
3474 addxtypeChild : function (tree, cntr) {
3475 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
3477 this.menuitems.add(comp);
3489 this.getEl().dom.innerHTML = '';
3490 this.menuitems.clear();
3504 * @class Roo.bootstrap.MenuItem
3505 * @extends Roo.bootstrap.Component
3506 * Bootstrap MenuItem class
3507 * @cfg {String} html the menu label
3508 * @cfg {String} href the link
3509 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
3510 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
3511 * @cfg {Boolean} active used on sidebars to highlight active itesm
3512 * @cfg {String} fa favicon to show on left of menu item.
3513 * @cfg {Roo.bootsrap.Menu} menu the child menu.
3517 * Create a new MenuItem
3518 * @param {Object} config The config object
3522 Roo.bootstrap.MenuItem = function(config){
3523 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
3528 * The raw click event for the entire grid.
3529 * @param {Roo.bootstrap.MenuItem} this
3530 * @param {Roo.EventObject} e
3536 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
3540 preventDefault: false,
3541 isContainer : false,
3545 getAutoCreate : function(){
3547 if(this.isContainer){
3550 cls: 'dropdown-menu-item '
3560 cls : 'dropdown-item',
3565 if (this.fa !== false) {
3568 cls : 'fa fa-' + this.fa
3577 cls: 'dropdown-menu-item',
3580 if (this.parent().type == 'treeview') {
3581 cfg.cls = 'treeview-menu';
3584 cfg.cls += ' active';
3589 anc.href = this.href || cfg.cn[0].href ;
3590 ctag.html = this.html || cfg.cn[0].html ;
3594 initEvents: function()
3596 if (this.parent().type == 'treeview') {
3597 this.el.select('a').on('click', this.onClick, this);
3601 this.menu.parentType = this.xtype;
3602 this.menu.triggerEl = this.el;
3603 this.menu = this.addxtype(Roo.apply({}, this.menu));
3607 onClick : function(e)
3609 Roo.log('item on click ');
3611 if(this.preventDefault){
3614 //this.parent().hideMenuItems();
3616 this.fireEvent('click', this, e);
3635 * @class Roo.bootstrap.MenuSeparator
3636 * @extends Roo.bootstrap.Component
3637 * Bootstrap MenuSeparator class
3640 * Create a new MenuItem
3641 * @param {Object} config The config object
3645 Roo.bootstrap.MenuSeparator = function(config){
3646 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
3649 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
3651 getAutoCreate : function(){
3670 * @class Roo.bootstrap.Modal
3671 * @extends Roo.bootstrap.Component
3672 * Bootstrap Modal class
3673 * @cfg {String} title Title of dialog
3674 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
3675 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
3676 * @cfg {Boolean} specificTitle default false
3677 * @cfg {Array} buttons Array of buttons or standard button set..
3678 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
3679 * @cfg {Boolean} animate default true
3680 * @cfg {Boolean} allow_close default true
3681 * @cfg {Boolean} fitwindow default false
3682 * @cfg {Number} width fixed width - usefull for chrome extension only really.
3683 * @cfg {Number} height fixed height - usefull for chrome extension only really.
3684 * @cfg {String} size (sm|lg) default empty
3685 * @cfg {Number} max_width set the max width of modal
3689 * Create a new Modal Dialog
3690 * @param {Object} config The config object
3693 Roo.bootstrap.Modal = function(config){
3694 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
3699 * The raw btnclick event for the button
3700 * @param {Roo.EventObject} e
3705 * Fire when dialog resize
3706 * @param {Roo.bootstrap.Modal} this
3707 * @param {Roo.EventObject} e
3711 this.buttons = this.buttons || [];
3714 this.tmpl = Roo.factory(this.tmpl);
3719 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
3721 title : 'test dialog',
3731 specificTitle: false,
3733 buttonPosition: 'right',
3756 onRender : function(ct, position)
3758 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
3761 var cfg = Roo.apply({}, this.getAutoCreate());
3764 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
3766 //if (!cfg.name.length) {
3770 cfg.cls += ' ' + this.cls;
3773 cfg.style = this.style;
3775 this.el = Roo.get(document.body).createChild(cfg, position);
3777 //var type = this.el.dom.type;
3780 if(this.tabIndex !== undefined){
3781 this.el.dom.setAttribute('tabIndex', this.tabIndex);
3784 this.dialogEl = this.el.select('.modal-dialog',true).first();
3785 this.bodyEl = this.el.select('.modal-body',true).first();
3786 this.closeEl = this.el.select('.modal-header .close', true).first();
3787 this.headerEl = this.el.select('.modal-header',true).first();
3788 this.titleEl = this.el.select('.modal-title',true).first();
3789 this.footerEl = this.el.select('.modal-footer',true).first();
3791 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
3793 //this.el.addClass("x-dlg-modal");
3795 if (this.buttons.length) {
3796 Roo.each(this.buttons, function(bb) {
3797 var b = Roo.apply({}, bb);
3798 b.xns = b.xns || Roo.bootstrap;
3799 b.xtype = b.xtype || 'Button';
3800 if (typeof(b.listeners) == 'undefined') {
3801 b.listeners = { click : this.onButtonClick.createDelegate(this) };
3804 var btn = Roo.factory(b);
3806 btn.render(this.getButtonContainer());
3810 // render the children.
3813 if(typeof(this.items) != 'undefined'){
3814 var items = this.items;
3817 for(var i =0;i < items.length;i++) {
3818 nitems.push(this.addxtype(Roo.apply({}, items[i])));
3822 this.items = nitems;
3824 // where are these used - they used to be body/close/footer
3828 //this.el.addClass([this.fieldClass, this.cls]);
3832 getAutoCreate : function()
3834 // we will default to modal-body-overflow - might need to remove or make optional later.
3836 cls : 'modal-body enable-modal-body-overflow ',
3837 html : this.html || ''
3842 cls : 'modal-title',
3846 if(this.specificTitle){
3852 if (this.allow_close && Roo.bootstrap.version == 3) {
3862 if (this.allow_close && Roo.bootstrap.version == 4) {
3872 if(this.size.length){
3873 size = 'modal-' + this.size;
3876 var footer = Roo.bootstrap.version == 3 ?
3878 cls : 'modal-footer',
3882 cls: 'btn-' + this.buttonPosition
3887 { // BS4 uses mr-auto on left buttons....
3888 cls : 'modal-footer'
3899 cls: "modal-dialog " + size,
3902 cls : "modal-content",
3905 cls : 'modal-header',
3920 modal.cls += ' fade';
3926 getChildContainer : function() {
3931 getButtonContainer : function() {
3933 return Roo.bootstrap.version == 4 ?
3934 this.el.select('.modal-footer',true).first()
3935 : this.el.select('.modal-footer div',true).first();
3938 initEvents : function()
3940 if (this.allow_close) {
3941 this.closeEl.on('click', this.hide, this);
3943 Roo.EventManager.onWindowResize(this.resize, this, true);
3951 this.maskEl.setSize(
3952 Roo.lib.Dom.getViewWidth(true),
3953 Roo.lib.Dom.getViewHeight(true)
3956 if (this.fitwindow) {
3960 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
3961 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
3966 if(this.max_width !== 0) {
3968 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
3971 this.setSize(w, this.height);
3975 if(this.max_height) {
3976 this.setSize(w,Math.min(
3978 Roo.lib.Dom.getViewportHeight(true) - 60
3984 if(!this.fit_content) {
3985 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
3989 this.setSize(w, Math.min(
3991 this.headerEl.getHeight() +
3992 this.footerEl.getHeight() +
3993 this.getChildHeight(this.bodyEl.dom.childNodes),
3994 Roo.lib.Dom.getViewportHeight(true) - 60)
4000 setSize : function(w,h)
4011 if (!this.rendered) {
4015 //this.el.setStyle('display', 'block');
4016 this.el.removeClass('hideing');
4017 this.el.dom.style.display='block';
4019 Roo.get(document.body).addClass('modal-open');
4021 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
4024 this.el.addClass('show');
4025 this.el.addClass('in');
4028 this.el.addClass('show');
4029 this.el.addClass('in');
4032 // not sure how we can show data in here..
4034 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
4037 Roo.get(document.body).addClass("x-body-masked");
4039 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
4040 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4041 this.maskEl.dom.style.display = 'block';
4042 this.maskEl.addClass('show');
4047 this.fireEvent('show', this);
4049 // set zindex here - otherwise it appears to be ignored...
4050 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4053 this.items.forEach( function(e) {
4054 e.layout ? e.layout() : false;
4062 if(this.fireEvent("beforehide", this) !== false){
4064 this.maskEl.removeClass('show');
4066 this.maskEl.dom.style.display = '';
4067 Roo.get(document.body).removeClass("x-body-masked");
4068 this.el.removeClass('in');
4069 this.el.select('.modal-dialog', true).first().setStyle('transform','');
4071 if(this.animate){ // why
4072 this.el.addClass('hideing');
4073 this.el.removeClass('show');
4075 if (!this.el.hasClass('hideing')) {
4076 return; // it's been shown again...
4079 this.el.dom.style.display='';
4081 Roo.get(document.body).removeClass('modal-open');
4082 this.el.removeClass('hideing');
4086 this.el.removeClass('show');
4087 this.el.dom.style.display='';
4088 Roo.get(document.body).removeClass('modal-open');
4091 this.fireEvent('hide', this);
4094 isVisible : function()
4097 return this.el.hasClass('show') && !this.el.hasClass('hideing');
4101 addButton : function(str, cb)
4105 var b = Roo.apply({}, { html : str } );
4106 b.xns = b.xns || Roo.bootstrap;
4107 b.xtype = b.xtype || 'Button';
4108 if (typeof(b.listeners) == 'undefined') {
4109 b.listeners = { click : cb.createDelegate(this) };
4112 var btn = Roo.factory(b);
4114 btn.render(this.getButtonContainer());
4120 setDefaultButton : function(btn)
4122 //this.el.select('.modal-footer').()
4125 resizeTo: function(w,h)
4127 this.dialogEl.setWidth(w);
4129 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
4131 this.bodyEl.setHeight(h - diff);
4133 this.fireEvent('resize', this);
4136 setContentSize : function(w, h)
4140 onButtonClick: function(btn,e)
4143 this.fireEvent('btnclick', btn.name, e);
4146 * Set the title of the Dialog
4147 * @param {String} str new Title
4149 setTitle: function(str) {
4150 this.titleEl.dom.innerHTML = str;
4153 * Set the body of the Dialog
4154 * @param {String} str new Title
4156 setBody: function(str) {
4157 this.bodyEl.dom.innerHTML = str;
4160 * Set the body of the Dialog using the template
4161 * @param {Obj} data - apply this data to the template and replace the body contents.
4163 applyBody: function(obj)
4166 Roo.log("Error - using apply Body without a template");
4169 this.tmpl.overwrite(this.bodyEl, obj);
4172 getChildHeight : function(child_nodes)
4176 child_nodes.length == 0
4181 var child_height = 0;
4183 for(var i = 0; i < child_nodes.length; i++) {
4186 * for modal with tabs...
4187 if(child_nodes[i].classList.contains('roo-layout-panel')) {
4189 var layout_childs = child_nodes[i].childNodes;
4191 for(var j = 0; j < layout_childs.length; j++) {
4193 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
4195 var layout_body_childs = layout_childs[j].childNodes;
4197 for(var k = 0; k < layout_body_childs.length; k++) {
4199 if(layout_body_childs[k].classList.contains('navbar')) {
4200 child_height += layout_body_childs[k].offsetHeight;
4204 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
4206 var layout_body_tab_childs = layout_body_childs[k].childNodes;
4208 for(var m = 0; m < layout_body_tab_childs.length; m++) {
4210 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
4211 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
4226 child_height += child_nodes[i].offsetHeight;
4227 // Roo.log(child_nodes[i].offsetHeight);
4230 return child_height;
4236 Roo.apply(Roo.bootstrap.Modal, {
4238 * Button config that displays a single OK button
4247 * Button config that displays Yes and No buttons
4263 * Button config that displays OK and Cancel buttons
4278 * Button config that displays Yes, No and Cancel buttons
4302 * messagebox - can be used as a replace
4306 * @class Roo.MessageBox
4307 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
4311 Roo.Msg.alert('Status', 'Changes saved successfully.');
4313 // Prompt for user data:
4314 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
4316 // process text value...
4320 // Show a dialog using config options:
4322 title:'Save Changes?',
4323 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
4324 buttons: Roo.Msg.YESNOCANCEL,
4331 Roo.bootstrap.MessageBox = function(){
4332 var dlg, opt, mask, waitTimer;
4333 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
4334 var buttons, activeTextEl, bwidth;
4338 var handleButton = function(button){
4340 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
4344 var handleHide = function(){
4346 dlg.el.removeClass(opt.cls);
4349 // Roo.TaskMgr.stop(waitTimer);
4350 // waitTimer = null;
4355 var updateButtons = function(b){
4358 buttons["ok"].hide();
4359 buttons["cancel"].hide();
4360 buttons["yes"].hide();
4361 buttons["no"].hide();
4362 dlg.footerEl.hide();
4366 dlg.footerEl.show();
4367 for(var k in buttons){
4368 if(typeof buttons[k] != "function"){
4371 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
4372 width += buttons[k].el.getWidth()+15;
4382 var handleEsc = function(d, k, e){
4383 if(opt && opt.closable !== false){
4393 * Returns a reference to the underlying {@link Roo.BasicDialog} element
4394 * @return {Roo.BasicDialog} The BasicDialog element
4396 getDialog : function(){
4398 dlg = new Roo.bootstrap.Modal( {
4401 //constraintoviewport:false,
4403 //collapsible : false,
4408 //buttonAlign:"center",
4409 closeClick : function(){
4410 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
4413 handleButton("cancel");
4418 dlg.on("hide", handleHide);
4420 //dlg.addKeyListener(27, handleEsc);
4422 this.buttons = buttons;
4423 var bt = this.buttonText;
4424 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
4425 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
4426 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
4427 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
4429 bodyEl = dlg.bodyEl.createChild({
4431 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
4432 '<textarea class="roo-mb-textarea"></textarea>' +
4433 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
4435 msgEl = bodyEl.dom.firstChild;
4436 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
4437 textboxEl.enableDisplayMode();
4438 textboxEl.addKeyListener([10,13], function(){
4439 if(dlg.isVisible() && opt && opt.buttons){
4442 }else if(opt.buttons.yes){
4443 handleButton("yes");
4447 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
4448 textareaEl.enableDisplayMode();
4449 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
4450 progressEl.enableDisplayMode();
4452 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
4453 var pf = progressEl.dom.firstChild;
4455 pp = Roo.get(pf.firstChild);
4456 pp.setHeight(pf.offsetHeight);
4464 * Updates the message box body text
4465 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
4466 * the XHTML-compliant non-breaking space character '&#160;')
4467 * @return {Roo.MessageBox} This message box
4469 updateText : function(text)
4471 if(!dlg.isVisible() && !opt.width){
4472 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
4473 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
4475 msgEl.innerHTML = text || ' ';
4477 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
4478 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
4480 Math.min(opt.width || cw , this.maxWidth),
4481 Math.max(opt.minWidth || this.minWidth, bwidth)
4484 activeTextEl.setWidth(w);
4486 if(dlg.isVisible()){
4487 dlg.fixedcenter = false;
4489 // to big, make it scroll. = But as usual stupid IE does not support
4492 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
4493 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
4494 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
4496 bodyEl.dom.style.height = '';
4497 bodyEl.dom.style.overflowY = '';
4500 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
4502 bodyEl.dom.style.overflowX = '';
4505 dlg.setContentSize(w, bodyEl.getHeight());
4506 if(dlg.isVisible()){
4507 dlg.fixedcenter = true;
4513 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
4514 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
4515 * @param {Number} value Any number between 0 and 1 (e.g., .5)
4516 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
4517 * @return {Roo.MessageBox} This message box
4519 updateProgress : function(value, text){
4521 this.updateText(text);
4524 if (pp) { // weird bug on my firefox - for some reason this is not defined
4525 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
4526 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
4532 * Returns true if the message box is currently displayed
4533 * @return {Boolean} True if the message box is visible, else false
4535 isVisible : function(){
4536 return dlg && dlg.isVisible();
4540 * Hides the message box if it is displayed
4543 if(this.isVisible()){
4549 * Displays a new message box, or reinitializes an existing message box, based on the config options
4550 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
4551 * The following config object properties are supported:
4553 Property Type Description
4554 ---------- --------------- ------------------------------------------------------------------------------------
4555 animEl String/Element An id or Element from which the message box should animate as it opens and
4556 closes (defaults to undefined)
4557 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
4558 cancel:'Bar'}), or false to not show any buttons (defaults to false)
4559 closable Boolean False to hide the top-right close button (defaults to true). Note that
4560 progress and wait dialogs will ignore this property and always hide the
4561 close button as they can only be closed programmatically.
4562 cls String A custom CSS class to apply to the message box element
4563 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
4564 displayed (defaults to 75)
4565 fn Function A callback function to execute after closing the dialog. The arguments to the
4566 function will be btn (the name of the button that was clicked, if applicable,
4567 e.g. "ok"), and text (the value of the active text field, if applicable).
4568 Progress and wait dialogs will ignore this option since they do not respond to
4569 user actions and can only be closed programmatically, so any required function
4570 should be called by the same code after it closes the dialog.
4571 icon String A CSS class that provides a background image to be used as an icon for
4572 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
4573 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
4574 minWidth Number The minimum width in pixels of the message box (defaults to 100)
4575 modal Boolean False to allow user interaction with the page while the message box is
4576 displayed (defaults to true)
4577 msg String A string that will replace the existing message box body text (defaults
4578 to the XHTML-compliant non-breaking space character ' ')
4579 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
4580 progress Boolean True to display a progress bar (defaults to false)
4581 progressText String The text to display inside the progress bar if progress = true (defaults to '')
4582 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
4583 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
4584 title String The title text
4585 value String The string value to set into the active textbox element if displayed
4586 wait Boolean True to display a progress bar (defaults to false)
4587 width Number The width of the dialog in pixels
4594 msg: 'Please enter your address:',
4596 buttons: Roo.MessageBox.OKCANCEL,
4599 animEl: 'addAddressBtn'
4602 * @param {Object} config Configuration options
4603 * @return {Roo.MessageBox} This message box
4605 show : function(options)
4608 // this causes nightmares if you show one dialog after another
4609 // especially on callbacks..
4611 if(this.isVisible()){
4614 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
4615 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
4616 Roo.log("New Dialog Message:" + options.msg )
4617 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
4618 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
4621 var d = this.getDialog();
4623 d.setTitle(opt.title || " ");
4624 d.closeEl.setDisplayed(opt.closable !== false);
4625 activeTextEl = textboxEl;
4626 opt.prompt = opt.prompt || (opt.multiline ? true : false);
4631 textareaEl.setHeight(typeof opt.multiline == "number" ?
4632 opt.multiline : this.defaultTextHeight);
4633 activeTextEl = textareaEl;
4642 progressEl.setDisplayed(opt.progress === true);
4644 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
4646 this.updateProgress(0);
4647 activeTextEl.dom.value = opt.value || "";
4649 dlg.setDefaultButton(activeTextEl);
4651 var bs = opt.buttons;
4655 }else if(bs && bs.yes){
4656 db = buttons["yes"];
4658 dlg.setDefaultButton(db);
4660 bwidth = updateButtons(opt.buttons);
4661 this.updateText(opt.msg);
4663 d.el.addClass(opt.cls);
4665 d.proxyDrag = opt.proxyDrag === true;
4666 d.modal = opt.modal !== false;
4667 d.mask = opt.modal !== false ? mask : false;
4669 // force it to the end of the z-index stack so it gets a cursor in FF
4670 document.body.appendChild(dlg.el.dom);
4671 d.animateTarget = null;
4672 d.show(options.animEl);
4678 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
4679 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
4680 * and closing the message box when the process is complete.
4681 * @param {String} title The title bar text
4682 * @param {String} msg The message box body text
4683 * @return {Roo.MessageBox} This message box
4685 progress : function(title, msg){
4692 minWidth: this.minProgressWidth,
4699 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
4700 * If a callback function is passed it will be called after the user clicks the button, and the
4701 * id of the button that was clicked will be passed as the only parameter to the callback
4702 * (could also be the top-right close button).
4703 * @param {String} title The title bar text
4704 * @param {String} msg The message box body text
4705 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4706 * @param {Object} scope (optional) The scope of the callback function
4707 * @return {Roo.MessageBox} This message box
4709 alert : function(title, msg, fn, scope)
4724 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
4725 * interaction while waiting for a long-running process to complete that does not have defined intervals.
4726 * You are responsible for closing the message box when the process is complete.
4727 * @param {String} msg The message box body text
4728 * @param {String} title (optional) The title bar text
4729 * @return {Roo.MessageBox} This message box
4731 wait : function(msg, title){
4742 waitTimer = Roo.TaskMgr.start({
4744 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
4752 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
4753 * If a callback function is passed it will be called after the user clicks either button, and the id of the
4754 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
4755 * @param {String} title The title bar text
4756 * @param {String} msg The message box body text
4757 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4758 * @param {Object} scope (optional) The scope of the callback function
4759 * @return {Roo.MessageBox} This message box
4761 confirm : function(title, msg, fn, scope){
4765 buttons: this.YESNO,
4774 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
4775 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
4776 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
4777 * (could also be the top-right close button) and the text that was entered will be passed as the two
4778 * parameters to the callback.
4779 * @param {String} title The title bar text
4780 * @param {String} msg The message box body text
4781 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4782 * @param {Object} scope (optional) The scope of the callback function
4783 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
4784 * property, or the height in pixels to create the textbox (defaults to false / single-line)
4785 * @return {Roo.MessageBox} This message box
4787 prompt : function(title, msg, fn, scope, multiline){
4791 buttons: this.OKCANCEL,
4796 multiline: multiline,
4803 * Button config that displays a single OK button
4808 * Button config that displays Yes and No buttons
4811 YESNO : {yes:true, no:true},
4813 * Button config that displays OK and Cancel buttons
4816 OKCANCEL : {ok:true, cancel:true},
4818 * Button config that displays Yes, No and Cancel buttons
4821 YESNOCANCEL : {yes:true, no:true, cancel:true},
4824 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
4827 defaultTextHeight : 75,
4829 * The maximum width in pixels of the message box (defaults to 600)
4834 * The minimum width in pixels of the message box (defaults to 100)
4839 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
4840 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
4843 minProgressWidth : 250,
4845 * An object containing the default button text strings that can be overriden for localized language support.
4846 * Supported properties are: ok, cancel, yes and no.
4847 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
4860 * Shorthand for {@link Roo.MessageBox}
4862 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
4863 Roo.Msg = Roo.Msg || Roo.MessageBox;
4872 * @class Roo.bootstrap.Navbar
4873 * @extends Roo.bootstrap.Component
4874 * Bootstrap Navbar class
4877 * Create a new Navbar
4878 * @param {Object} config The config object
4882 Roo.bootstrap.Navbar = function(config){
4883 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
4887 * @event beforetoggle
4888 * Fire before toggle the menu
4889 * @param {Roo.EventObject} e
4891 "beforetoggle" : true
4895 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
4904 getAutoCreate : function(){
4907 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
4911 initEvents :function ()
4913 //Roo.log(this.el.select('.navbar-toggle',true));
4914 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
4921 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
4923 var size = this.el.getSize();
4924 this.maskEl.setSize(size.width, size.height);
4925 this.maskEl.enableDisplayMode("block");
4934 getChildContainer : function()
4936 if (this.el && this.el.select('.collapse').getCount()) {
4937 return this.el.select('.collapse',true).first();
4952 onToggle : function()
4955 if(this.fireEvent('beforetoggle', this) === false){
4958 var ce = this.el.select('.navbar-collapse',true).first();
4960 if (!ce.hasClass('show')) {
4970 * Expand the navbar pulldown
4972 expand : function ()
4975 var ce = this.el.select('.navbar-collapse',true).first();
4976 if (ce.hasClass('collapsing')) {
4979 ce.dom.style.height = '';
4981 ce.addClass('in'); // old...
4982 ce.removeClass('collapse');
4983 ce.addClass('show');
4984 var h = ce.getHeight();
4986 ce.removeClass('show');
4987 // at this point we should be able to see it..
4988 ce.addClass('collapsing');
4990 ce.setHeight(0); // resize it ...
4991 ce.on('transitionend', function() {
4992 //Roo.log('done transition');
4993 ce.removeClass('collapsing');
4994 ce.addClass('show');
4995 ce.removeClass('collapse');
4997 ce.dom.style.height = '';
4998 }, this, { single: true} );
5000 ce.dom.scrollTop = 0;
5003 * Collapse the navbar pulldown
5005 collapse : function()
5007 var ce = this.el.select('.navbar-collapse',true).first();
5009 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
5010 // it's collapsed or collapsing..
5013 ce.removeClass('in'); // old...
5014 ce.setHeight(ce.getHeight());
5015 ce.removeClass('show');
5016 ce.addClass('collapsing');
5018 ce.on('transitionend', function() {
5019 ce.dom.style.height = '';
5020 ce.removeClass('collapsing');
5021 ce.addClass('collapse');
5022 }, this, { single: true} );
5042 * @class Roo.bootstrap.NavSimplebar
5043 * @extends Roo.bootstrap.Navbar
5044 * Bootstrap Sidebar class
5046 * @cfg {Boolean} inverse is inverted color
5048 * @cfg {String} type (nav | pills | tabs)
5049 * @cfg {Boolean} arrangement stacked | justified
5050 * @cfg {String} align (left | right) alignment
5052 * @cfg {Boolean} main (true|false) main nav bar? default false
5053 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
5055 * @cfg {String} tag (header|footer|nav|div) default is nav
5057 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
5061 * Create a new Sidebar
5062 * @param {Object} config The config object
5066 Roo.bootstrap.NavSimplebar = function(config){
5067 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
5070 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
5086 getAutoCreate : function(){
5090 tag : this.tag || 'div',
5091 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
5093 if (['light','white'].indexOf(this.weight) > -1) {
5094 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5096 cfg.cls += ' bg-' + this.weight;
5099 cfg.cls += ' navbar-inverse';
5103 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
5105 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
5114 cls: 'nav nav-' + this.xtype,
5120 this.type = this.type || 'nav';
5121 if (['tabs','pills'].indexOf(this.type) != -1) {
5122 cfg.cn[0].cls += ' nav-' + this.type
5126 if (this.type!=='nav') {
5127 Roo.log('nav type must be nav/tabs/pills')
5129 cfg.cn[0].cls += ' navbar-nav'
5135 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
5136 cfg.cn[0].cls += ' nav-' + this.arrangement;
5140 if (this.align === 'right') {
5141 cfg.cn[0].cls += ' navbar-right';
5166 * navbar-expand-md fixed-top
5170 * @class Roo.bootstrap.NavHeaderbar
5171 * @extends Roo.bootstrap.NavSimplebar
5172 * Bootstrap Sidebar class
5174 * @cfg {String} brand what is brand
5175 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
5176 * @cfg {String} brand_href href of the brand
5177 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
5178 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
5179 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
5180 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
5183 * Create a new Sidebar
5184 * @param {Object} config The config object
5188 Roo.bootstrap.NavHeaderbar = function(config){
5189 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
5193 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
5200 desktopCenter : false,
5203 getAutoCreate : function(){
5206 tag: this.nav || 'nav',
5207 cls: 'navbar navbar-expand-md',
5213 if (this.desktopCenter) {
5214 cn.push({cls : 'container', cn : []});
5222 cls: 'navbar-toggle navbar-toggler',
5223 'data-toggle': 'collapse',
5228 html: 'Toggle navigation'
5232 cls: 'icon-bar navbar-toggler-icon'
5245 cn.push( Roo.bootstrap.version == 4 ? btn : {
5247 cls: 'navbar-header',
5256 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse collapse navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
5260 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
5262 if (['light','white'].indexOf(this.weight) > -1) {
5263 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5265 cfg.cls += ' bg-' + this.weight;
5268 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
5269 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
5271 // tag can override this..
5273 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
5276 if (this.brand !== '') {
5277 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
5278 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
5280 href: this.brand_href ? this.brand_href : '#',
5281 cls: 'navbar-brand',
5289 cfg.cls += ' main-nav';
5297 getHeaderChildContainer : function()
5299 if (this.srButton && this.el.select('.navbar-header').getCount()) {
5300 return this.el.select('.navbar-header',true).first();
5303 return this.getChildContainer();
5306 getChildContainer : function()
5309 return this.el.select('.roo-navbar-collapse',true).first();
5314 initEvents : function()
5316 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
5318 if (this.autohide) {
5323 Roo.get(document).on('scroll',function(e) {
5324 var ns = Roo.get(document).getScroll().top;
5325 var os = prevScroll;
5329 ft.removeClass('slideDown');
5330 ft.addClass('slideUp');
5333 ft.removeClass('slideUp');
5334 ft.addClass('slideDown');
5355 * @class Roo.bootstrap.NavSidebar
5356 * @extends Roo.bootstrap.Navbar
5357 * Bootstrap Sidebar class
5360 * Create a new Sidebar
5361 * @param {Object} config The config object
5365 Roo.bootstrap.NavSidebar = function(config){
5366 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
5369 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
5371 sidebar : true, // used by Navbar Item and NavbarGroup at present...
5373 getAutoCreate : function(){
5378 cls: 'sidebar sidebar-nav'
5400 * @class Roo.bootstrap.NavGroup
5401 * @extends Roo.bootstrap.Component
5402 * Bootstrap NavGroup class
5403 * @cfg {String} align (left|right)
5404 * @cfg {Boolean} inverse
5405 * @cfg {String} type (nav|pills|tab) default nav
5406 * @cfg {String} navId - reference Id for navbar.
5410 * Create a new nav group
5411 * @param {Object} config The config object
5414 Roo.bootstrap.NavGroup = function(config){
5415 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
5418 Roo.bootstrap.NavGroup.register(this);
5422 * Fires when the active item changes
5423 * @param {Roo.bootstrap.NavGroup} this
5424 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
5425 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
5432 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
5443 getAutoCreate : function()
5445 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
5451 if (Roo.bootstrap.version == 4) {
5452 if (['tabs','pills'].indexOf(this.type) != -1) {
5453 cfg.cls += ' nav-' + this.type;
5455 // trying to remove so header bar can right align top?
5456 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
5457 // do not use on header bar...
5458 cfg.cls += ' navbar-nav';
5463 if (['tabs','pills'].indexOf(this.type) != -1) {
5464 cfg.cls += ' nav-' + this.type
5466 if (this.type !== 'nav') {
5467 Roo.log('nav type must be nav/tabs/pills')
5469 cfg.cls += ' navbar-nav'
5473 if (this.parent() && this.parent().sidebar) {
5476 cls: 'dashboard-menu sidebar-menu'
5482 if (this.form === true) {
5485 cls: 'navbar-form form-inline'
5487 //nav navbar-right ml-md-auto
5488 if (this.align === 'right') {
5489 cfg.cls += ' navbar-right ml-md-auto';
5491 cfg.cls += ' navbar-left';
5495 if (this.align === 'right') {
5496 cfg.cls += ' navbar-right ml-md-auto';
5498 cfg.cls += ' mr-auto';
5502 cfg.cls += ' navbar-inverse';
5510 * sets the active Navigation item
5511 * @param {Roo.bootstrap.NavItem} the new current navitem
5513 setActiveItem : function(item)
5516 Roo.each(this.navItems, function(v){
5521 v.setActive(false, true);
5528 item.setActive(true, true);
5529 this.fireEvent('changed', this, item, prev);
5534 * gets the active Navigation item
5535 * @return {Roo.bootstrap.NavItem} the current navitem
5537 getActive : function()
5541 Roo.each(this.navItems, function(v){
5552 indexOfNav : function()
5556 Roo.each(this.navItems, function(v,i){
5567 * adds a Navigation item
5568 * @param {Roo.bootstrap.NavItem} the navitem to add
5570 addItem : function(cfg)
5572 if (this.form && Roo.bootstrap.version == 4) {
5575 var cn = new Roo.bootstrap.NavItem(cfg);
5577 cn.parentId = this.id;
5578 cn.onRender(this.el, null);
5582 * register a Navigation item
5583 * @param {Roo.bootstrap.NavItem} the navitem to add
5585 register : function(item)
5587 this.navItems.push( item);
5588 item.navId = this.navId;
5593 * clear all the Navigation item
5596 clearAll : function()
5599 this.el.dom.innerHTML = '';
5602 getNavItem: function(tabId)
5605 Roo.each(this.navItems, function(e) {
5606 if (e.tabId == tabId) {
5616 setActiveNext : function()
5618 var i = this.indexOfNav(this.getActive());
5619 if (i > this.navItems.length) {
5622 this.setActiveItem(this.navItems[i+1]);
5624 setActivePrev : function()
5626 var i = this.indexOfNav(this.getActive());
5630 this.setActiveItem(this.navItems[i-1]);
5632 clearWasActive : function(except) {
5633 Roo.each(this.navItems, function(e) {
5634 if (e.tabId != except.tabId && e.was_active) {
5635 e.was_active = false;
5642 getWasActive : function ()
5645 Roo.each(this.navItems, function(e) {
5660 Roo.apply(Roo.bootstrap.NavGroup, {
5664 * register a Navigation Group
5665 * @param {Roo.bootstrap.NavGroup} the navgroup to add
5667 register : function(navgrp)
5669 this.groups[navgrp.navId] = navgrp;
5673 * fetch a Navigation Group based on the navigation ID
5674 * @param {string} the navgroup to add
5675 * @returns {Roo.bootstrap.NavGroup} the navgroup
5677 get: function(navId) {
5678 if (typeof(this.groups[navId]) == 'undefined') {
5680 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
5682 return this.groups[navId] ;
5697 * @class Roo.bootstrap.NavItem
5698 * @extends Roo.bootstrap.Component
5699 * Bootstrap Navbar.NavItem class
5700 * @cfg {String} href link to
5701 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
5703 * @cfg {String} html content of button
5704 * @cfg {String} badge text inside badge
5705 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
5706 * @cfg {String} glyphicon DEPRICATED - use fa
5707 * @cfg {String} icon DEPRICATED - use fa
5708 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
5709 * @cfg {Boolean} active Is item active
5710 * @cfg {Boolean} disabled Is item disabled
5712 * @cfg {Boolean} preventDefault (true | false) default false
5713 * @cfg {String} tabId the tab that this item activates.
5714 * @cfg {String} tagtype (a|span) render as a href or span?
5715 * @cfg {Boolean} animateRef (true|false) link to element default false
5718 * Create a new Navbar Item
5719 * @param {Object} config The config object
5721 Roo.bootstrap.NavItem = function(config){
5722 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
5727 * The raw click event for the entire grid.
5728 * @param {Roo.EventObject} e
5733 * Fires when the active item active state changes
5734 * @param {Roo.bootstrap.NavItem} this
5735 * @param {boolean} state the new state
5741 * Fires when scroll to element
5742 * @param {Roo.bootstrap.NavItem} this
5743 * @param {Object} options
5744 * @param {Roo.EventObject} e
5752 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
5761 preventDefault : false,
5769 button_outline : false,
5773 getAutoCreate : function(){
5781 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
5783 if (this.disabled) {
5784 cfg.cls += ' disabled';
5788 if (this.button_weight.length) {
5789 cfg.tag = this.href ? 'a' : 'button';
5790 cfg.html = this.html || '';
5791 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
5793 cfg.href = this.href;
5796 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
5799 // menu .. should add dropdown-menu class - so no need for carat..
5801 if (this.badge !== '') {
5803 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
5808 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
5812 href : this.href || "#",
5813 html: this.html || ''
5816 if (this.tagtype == 'a') {
5817 cfg.cn[0].cls = 'nav-link';
5820 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
5823 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
5825 if(this.glyphicon) {
5826 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
5831 cfg.cn[0].html += " <span class='caret'></span>";
5835 if (this.badge !== '') {
5837 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
5845 onRender : function(ct, position)
5847 // Roo.log("Call onRender: " + this.xtype);
5848 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
5852 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
5853 this.navLink = this.el.select('.nav-link',true).first();
5858 initEvents: function()
5860 if (typeof (this.menu) != 'undefined') {
5861 this.menu.parentType = this.xtype;
5862 this.menu.triggerEl = this.el;
5863 this.menu = this.addxtype(Roo.apply({}, this.menu));
5866 this.el.select('a',true).on('click', this.onClick, this);
5868 if(this.tagtype == 'span'){
5869 this.el.select('span',true).on('click', this.onClick, this);
5872 // at this point parent should be available..
5873 this.parent().register(this);
5876 onClick : function(e)
5878 if (e.getTarget('.dropdown-menu-item')) {
5879 // did you click on a menu itemm.... - then don't trigger onclick..
5884 this.preventDefault ||
5887 Roo.log("NavItem - prevent Default?");
5891 if (this.disabled) {
5895 var tg = Roo.bootstrap.TabGroup.get(this.navId);
5896 if (tg && tg.transition) {
5897 Roo.log("waiting for the transitionend");
5903 //Roo.log("fire event clicked");
5904 if(this.fireEvent('click', this, e) === false){
5908 if(this.tagtype == 'span'){
5912 //Roo.log(this.href);
5913 var ael = this.el.select('a',true).first();
5916 if(ael && this.animateRef && this.href.indexOf('#') > -1){
5917 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
5918 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
5919 return; // ignore... - it's a 'hash' to another page.
5921 Roo.log("NavItem - prevent Default?");
5923 this.scrollToElement(e);
5927 var p = this.parent();
5929 if (['tabs','pills'].indexOf(p.type)!==-1) {
5930 if (typeof(p.setActiveItem) !== 'undefined') {
5931 p.setActiveItem(this);
5935 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
5936 if (p.parentType == 'NavHeaderbar' && !this.menu) {
5937 // remove the collapsed menu expand...
5938 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
5942 isActive: function () {
5945 setActive : function(state, fire, is_was_active)
5947 if (this.active && !state && this.navId) {
5948 this.was_active = true;
5949 var nv = Roo.bootstrap.NavGroup.get(this.navId);
5951 nv.clearWasActive(this);
5955 this.active = state;
5958 this.el.removeClass('active');
5959 this.navLink ? this.navLink.removeClass('active') : false;
5960 } else if (!this.el.hasClass('active')) {
5962 this.el.addClass('active');
5963 if (Roo.bootstrap.version == 4 && this.navLink ) {
5964 this.navLink.addClass('active');
5969 this.fireEvent('changed', this, state);
5972 // show a panel if it's registered and related..
5974 if (!this.navId || !this.tabId || !state || is_was_active) {
5978 var tg = Roo.bootstrap.TabGroup.get(this.navId);
5982 var pan = tg.getPanelByName(this.tabId);
5986 // if we can not flip to new panel - go back to old nav highlight..
5987 if (false == tg.showPanel(pan)) {
5988 var nv = Roo.bootstrap.NavGroup.get(this.navId);
5990 var onav = nv.getWasActive();
5992 onav.setActive(true, false, true);
6001 // this should not be here...
6002 setDisabled : function(state)
6004 this.disabled = state;
6006 this.el.removeClass('disabled');
6007 } else if (!this.el.hasClass('disabled')) {
6008 this.el.addClass('disabled');
6014 * Fetch the element to display the tooltip on.
6015 * @return {Roo.Element} defaults to this.el
6017 tooltipEl : function()
6019 return this.el.select('' + this.tagtype + '', true).first();
6022 scrollToElement : function(e)
6024 var c = document.body;
6027 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
6029 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
6030 c = document.documentElement;
6033 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
6039 var o = target.calcOffsetsTo(c);
6046 this.fireEvent('scrollto', this, options, e);
6048 Roo.get(c).scrollTo('top', options.value, true);
6061 * <span> icon </span>
6062 * <span> text </span>
6063 * <span>badge </span>
6067 * @class Roo.bootstrap.NavSidebarItem
6068 * @extends Roo.bootstrap.NavItem
6069 * Bootstrap Navbar.NavSidebarItem class
6070 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
6071 * {Boolean} open is the menu open
6072 * {Boolean} buttonView use button as the tigger el rather that a (default false)
6073 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
6074 * {String} buttonSize (sm|md|lg)the extra classes for the button
6075 * {Boolean} showArrow show arrow next to the text (default true)
6077 * Create a new Navbar Button
6078 * @param {Object} config The config object
6080 Roo.bootstrap.NavSidebarItem = function(config){
6081 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
6086 * The raw click event for the entire grid.
6087 * @param {Roo.EventObject} e
6092 * Fires when the active item active state changes
6093 * @param {Roo.bootstrap.NavSidebarItem} this
6094 * @param {boolean} state the new state
6102 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
6104 badgeWeight : 'default',
6110 buttonWeight : 'default',
6116 getAutoCreate : function(){
6121 href : this.href || '#',
6127 if(this.buttonView){
6130 href : this.href || '#',
6131 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
6144 cfg.cls += ' active';
6147 if (this.disabled) {
6148 cfg.cls += ' disabled';
6151 cfg.cls += ' open x-open';
6154 if (this.glyphicon || this.icon) {
6155 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
6156 a.cn.push({ tag : 'i', cls : c }) ;
6159 if(!this.buttonView){
6162 html : this.html || ''
6169 if (this.badge !== '') {
6170 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
6176 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
6179 a.cls += ' dropdown-toggle treeview' ;
6185 initEvents : function()
6187 if (typeof (this.menu) != 'undefined') {
6188 this.menu.parentType = this.xtype;
6189 this.menu.triggerEl = this.el;
6190 this.menu = this.addxtype(Roo.apply({}, this.menu));
6193 this.el.on('click', this.onClick, this);
6195 if(this.badge !== ''){
6196 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
6201 onClick : function(e)
6208 if(this.preventDefault){
6212 this.fireEvent('click', this, e);
6215 disable : function()
6217 this.setDisabled(true);
6222 this.setDisabled(false);
6225 setDisabled : function(state)
6227 if(this.disabled == state){
6231 this.disabled = state;
6234 this.el.addClass('disabled');
6238 this.el.removeClass('disabled');
6243 setActive : function(state)
6245 if(this.active == state){
6249 this.active = state;
6252 this.el.addClass('active');
6256 this.el.removeClass('active');
6261 isActive: function ()
6266 setBadge : function(str)
6272 this.badgeEl.dom.innerHTML = str;
6289 * @class Roo.bootstrap.Row
6290 * @extends Roo.bootstrap.Component
6291 * Bootstrap Row class (contains columns...)
6295 * @param {Object} config The config object
6298 Roo.bootstrap.Row = function(config){
6299 Roo.bootstrap.Row.superclass.constructor.call(this, config);
6302 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
6304 getAutoCreate : function(){
6323 * @class Roo.bootstrap.Pagination
6324 * @extends Roo.bootstrap.Component
6325 * Bootstrap Pagination class
6326 * @cfg {String} size xs | sm | md | lg
6327 * @cfg {Boolean} inverse false | true
6330 * Create a new Pagination
6331 * @param {Object} config The config object
6334 Roo.bootstrap.Pagination = function(config){
6335 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
6338 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
6344 getAutoCreate : function(){
6350 cfg.cls += ' inverse';
6356 cfg.cls += " " + this.cls;
6374 * @class Roo.bootstrap.PaginationItem
6375 * @extends Roo.bootstrap.Component
6376 * Bootstrap PaginationItem class
6377 * @cfg {String} html text
6378 * @cfg {String} href the link
6379 * @cfg {Boolean} preventDefault (true | false) default true
6380 * @cfg {Boolean} active (true | false) default false
6381 * @cfg {Boolean} disabled default false
6385 * Create a new PaginationItem
6386 * @param {Object} config The config object
6390 Roo.bootstrap.PaginationItem = function(config){
6391 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
6396 * The raw click event for the entire grid.
6397 * @param {Roo.EventObject} e
6403 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
6407 preventDefault: true,
6412 getAutoCreate : function(){
6418 href : this.href ? this.href : '#',
6419 html : this.html ? this.html : ''
6429 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
6433 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
6439 initEvents: function() {
6441 this.el.on('click', this.onClick, this);
6444 onClick : function(e)
6446 Roo.log('PaginationItem on click ');
6447 if(this.preventDefault){
6455 this.fireEvent('click', this, e);
6471 * @class Roo.bootstrap.Slider
6472 * @extends Roo.bootstrap.Component
6473 * Bootstrap Slider class
6476 * Create a new Slider
6477 * @param {Object} config The config object
6480 Roo.bootstrap.Slider = function(config){
6481 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
6484 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
6486 getAutoCreate : function(){
6490 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
6494 cls: 'ui-slider-handle ui-state-default ui-corner-all'
6506 * Ext JS Library 1.1.1
6507 * Copyright(c) 2006-2007, Ext JS, LLC.
6509 * Originally Released Under LGPL - original licence link has changed is not relivant.
6512 * <script type="text/javascript">
6517 * @class Roo.grid.ColumnModel
6518 * @extends Roo.util.Observable
6519 * This is the default implementation of a ColumnModel used by the Grid. It defines
6520 * the columns in the grid.
6523 var colModel = new Roo.grid.ColumnModel([
6524 {header: "Ticker", width: 60, sortable: true, locked: true},
6525 {header: "Company Name", width: 150, sortable: true},
6526 {header: "Market Cap.", width: 100, sortable: true},
6527 {header: "$ Sales", width: 100, sortable: true, renderer: money},
6528 {header: "Employees", width: 100, sortable: true, resizable: false}
6533 * The config options listed for this class are options which may appear in each
6534 * individual column definition.
6535 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
6537 * @param {Object} config An Array of column config objects. See this class's
6538 * config objects for details.
6540 Roo.grid.ColumnModel = function(config){
6542 * The config passed into the constructor
6544 this.config = config;
6547 // if no id, create one
6548 // if the column does not have a dataIndex mapping,
6549 // map it to the order it is in the config
6550 for(var i = 0, len = config.length; i < len; i++){
6552 if(typeof c.dataIndex == "undefined"){
6555 if(typeof c.renderer == "string"){
6556 c.renderer = Roo.util.Format[c.renderer];
6558 if(typeof c.id == "undefined"){
6561 if(c.editor && c.editor.xtype){
6562 c.editor = Roo.factory(c.editor, Roo.grid);
6564 if(c.editor && c.editor.isFormField){
6565 c.editor = new Roo.grid.GridEditor(c.editor);
6567 this.lookup[c.id] = c;
6571 * The width of columns which have no width specified (defaults to 100)
6574 this.defaultWidth = 100;
6577 * Default sortable of columns which have no sortable specified (defaults to false)
6580 this.defaultSortable = false;
6584 * @event widthchange
6585 * Fires when the width of a column changes.
6586 * @param {ColumnModel} this
6587 * @param {Number} columnIndex The column index
6588 * @param {Number} newWidth The new width
6590 "widthchange": true,
6592 * @event headerchange
6593 * Fires when the text of a header changes.
6594 * @param {ColumnModel} this
6595 * @param {Number} columnIndex The column index
6596 * @param {Number} newText The new header text
6598 "headerchange": true,
6600 * @event hiddenchange
6601 * Fires when a column is hidden or "unhidden".
6602 * @param {ColumnModel} this
6603 * @param {Number} columnIndex The column index
6604 * @param {Boolean} hidden true if hidden, false otherwise
6606 "hiddenchange": true,
6608 * @event columnmoved
6609 * Fires when a column is moved.
6610 * @param {ColumnModel} this
6611 * @param {Number} oldIndex
6612 * @param {Number} newIndex
6614 "columnmoved" : true,
6616 * @event columlockchange
6617 * Fires when a column's locked state is changed
6618 * @param {ColumnModel} this
6619 * @param {Number} colIndex
6620 * @param {Boolean} locked true if locked
6622 "columnlockchange" : true
6624 Roo.grid.ColumnModel.superclass.constructor.call(this);
6626 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
6628 * @cfg {String} header The header text to display in the Grid view.
6631 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
6632 * {@link Roo.data.Record} definition from which to draw the column's value. If not
6633 * specified, the column's index is used as an index into the Record's data Array.
6636 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
6637 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
6640 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
6641 * Defaults to the value of the {@link #defaultSortable} property.
6642 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
6645 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
6648 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
6651 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
6654 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
6657 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
6658 * given the cell's data value. See {@link #setRenderer}. If not specified, the
6659 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
6660 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
6663 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
6666 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
6669 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
6672 * @cfg {String} cursor (Optional)
6675 * @cfg {String} tooltip (Optional)
6678 * @cfg {Number} xs (Optional)
6681 * @cfg {Number} sm (Optional)
6684 * @cfg {Number} md (Optional)
6687 * @cfg {Number} lg (Optional)
6690 * Returns the id of the column at the specified index.
6691 * @param {Number} index The column index
6692 * @return {String} the id
6694 getColumnId : function(index){
6695 return this.config[index].id;
6699 * Returns the column for a specified id.
6700 * @param {String} id The column id
6701 * @return {Object} the column
6703 getColumnById : function(id){
6704 return this.lookup[id];
6709 * Returns the column for a specified dataIndex.
6710 * @param {String} dataIndex The column dataIndex
6711 * @return {Object|Boolean} the column or false if not found
6713 getColumnByDataIndex: function(dataIndex){
6714 var index = this.findColumnIndex(dataIndex);
6715 return index > -1 ? this.config[index] : false;
6719 * Returns the index for a specified column id.
6720 * @param {String} id The column id
6721 * @return {Number} the index, or -1 if not found
6723 getIndexById : function(id){
6724 for(var i = 0, len = this.config.length; i < len; i++){
6725 if(this.config[i].id == id){
6733 * Returns the index for a specified column dataIndex.
6734 * @param {String} dataIndex The column dataIndex
6735 * @return {Number} the index, or -1 if not found
6738 findColumnIndex : function(dataIndex){
6739 for(var i = 0, len = this.config.length; i < len; i++){
6740 if(this.config[i].dataIndex == dataIndex){
6748 moveColumn : function(oldIndex, newIndex){
6749 var c = this.config[oldIndex];
6750 this.config.splice(oldIndex, 1);
6751 this.config.splice(newIndex, 0, c);
6752 this.dataMap = null;
6753 this.fireEvent("columnmoved", this, oldIndex, newIndex);
6756 isLocked : function(colIndex){
6757 return this.config[colIndex].locked === true;
6760 setLocked : function(colIndex, value, suppressEvent){
6761 if(this.isLocked(colIndex) == value){
6764 this.config[colIndex].locked = value;
6766 this.fireEvent("columnlockchange", this, colIndex, value);
6770 getTotalLockedWidth : function(){
6772 for(var i = 0; i < this.config.length; i++){
6773 if(this.isLocked(i) && !this.isHidden(i)){
6774 this.totalWidth += this.getColumnWidth(i);
6780 getLockedCount : function(){
6781 for(var i = 0, len = this.config.length; i < len; i++){
6782 if(!this.isLocked(i)){
6787 return this.config.length;
6791 * Returns the number of columns.
6794 getColumnCount : function(visibleOnly){
6795 if(visibleOnly === true){
6797 for(var i = 0, len = this.config.length; i < len; i++){
6798 if(!this.isHidden(i)){
6804 return this.config.length;
6808 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
6809 * @param {Function} fn
6810 * @param {Object} scope (optional)
6811 * @return {Array} result
6813 getColumnsBy : function(fn, scope){
6815 for(var i = 0, len = this.config.length; i < len; i++){
6816 var c = this.config[i];
6817 if(fn.call(scope||this, c, i) === true){
6825 * Returns true if the specified column is sortable.
6826 * @param {Number} col The column index
6829 isSortable : function(col){
6830 if(typeof this.config[col].sortable == "undefined"){
6831 return this.defaultSortable;
6833 return this.config[col].sortable;
6837 * Returns the rendering (formatting) function defined for the column.
6838 * @param {Number} col The column index.
6839 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
6841 getRenderer : function(col){
6842 if(!this.config[col].renderer){
6843 return Roo.grid.ColumnModel.defaultRenderer;
6845 return this.config[col].renderer;
6849 * Sets the rendering (formatting) function for a column.
6850 * @param {Number} col The column index
6851 * @param {Function} fn The function to use to process the cell's raw data
6852 * to return HTML markup for the grid view. The render function is called with
6853 * the following parameters:<ul>
6854 * <li>Data value.</li>
6855 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
6856 * <li>css A CSS style string to apply to the table cell.</li>
6857 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
6858 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
6859 * <li>Row index</li>
6860 * <li>Column index</li>
6861 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
6863 setRenderer : function(col, fn){
6864 this.config[col].renderer = fn;
6868 * Returns the width for the specified column.
6869 * @param {Number} col The column index
6872 getColumnWidth : function(col){
6873 return this.config[col].width * 1 || this.defaultWidth;
6877 * Sets the width for a column.
6878 * @param {Number} col The column index
6879 * @param {Number} width The new width
6881 setColumnWidth : function(col, width, suppressEvent){
6882 this.config[col].width = width;
6883 this.totalWidth = null;
6885 this.fireEvent("widthchange", this, col, width);
6890 * Returns the total width of all columns.
6891 * @param {Boolean} includeHidden True to include hidden column widths
6894 getTotalWidth : function(includeHidden){
6895 if(!this.totalWidth){
6896 this.totalWidth = 0;
6897 for(var i = 0, len = this.config.length; i < len; i++){
6898 if(includeHidden || !this.isHidden(i)){
6899 this.totalWidth += this.getColumnWidth(i);
6903 return this.totalWidth;
6907 * Returns the header for the specified column.
6908 * @param {Number} col The column index
6911 getColumnHeader : function(col){
6912 return this.config[col].header;
6916 * Sets the header for a column.
6917 * @param {Number} col The column index
6918 * @param {String} header The new header
6920 setColumnHeader : function(col, header){
6921 this.config[col].header = header;
6922 this.fireEvent("headerchange", this, col, header);
6926 * Returns the tooltip for the specified column.
6927 * @param {Number} col The column index
6930 getColumnTooltip : function(col){
6931 return this.config[col].tooltip;
6934 * Sets the tooltip for a column.
6935 * @param {Number} col The column index
6936 * @param {String} tooltip The new tooltip
6938 setColumnTooltip : function(col, tooltip){
6939 this.config[col].tooltip = tooltip;
6943 * Returns the dataIndex for the specified column.
6944 * @param {Number} col The column index
6947 getDataIndex : function(col){
6948 return this.config[col].dataIndex;
6952 * Sets the dataIndex for a column.
6953 * @param {Number} col The column index
6954 * @param {Number} dataIndex The new dataIndex
6956 setDataIndex : function(col, dataIndex){
6957 this.config[col].dataIndex = dataIndex;
6963 * Returns true if the cell is editable.
6964 * @param {Number} colIndex The column index
6965 * @param {Number} rowIndex The row index - this is nto actually used..?
6968 isCellEditable : function(colIndex, rowIndex){
6969 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6973 * Returns the editor defined for the cell/column.
6974 * return false or null to disable editing.
6975 * @param {Number} colIndex The column index
6976 * @param {Number} rowIndex The row index
6979 getCellEditor : function(colIndex, rowIndex){
6980 return this.config[colIndex].editor;
6984 * Sets if a column is editable.
6985 * @param {Number} col The column index
6986 * @param {Boolean} editable True if the column is editable
6988 setEditable : function(col, editable){
6989 this.config[col].editable = editable;
6994 * Returns true if the column is hidden.
6995 * @param {Number} colIndex The column index
6998 isHidden : function(colIndex){
6999 return this.config[colIndex].hidden;
7004 * Returns true if the column width cannot be changed
7006 isFixed : function(colIndex){
7007 return this.config[colIndex].fixed;
7011 * Returns true if the column can be resized
7014 isResizable : function(colIndex){
7015 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
7018 * Sets if a column is hidden.
7019 * @param {Number} colIndex The column index
7020 * @param {Boolean} hidden True if the column is hidden
7022 setHidden : function(colIndex, hidden){
7023 this.config[colIndex].hidden = hidden;
7024 this.totalWidth = null;
7025 this.fireEvent("hiddenchange", this, colIndex, hidden);
7029 * Sets the editor for a column.
7030 * @param {Number} col The column index
7031 * @param {Object} editor The editor object
7033 setEditor : function(col, editor){
7034 this.config[col].editor = editor;
7038 Roo.grid.ColumnModel.defaultRenderer = function(value)
7040 if(typeof value == "object") {
7043 if(typeof value == "string" && value.length < 1){
7047 return String.format("{0}", value);
7050 // Alias for backwards compatibility
7051 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
7054 * Ext JS Library 1.1.1
7055 * Copyright(c) 2006-2007, Ext JS, LLC.
7057 * Originally Released Under LGPL - original licence link has changed is not relivant.
7060 * <script type="text/javascript">
7064 * @class Roo.LoadMask
7065 * A simple utility class for generically masking elements while loading data. If the element being masked has
7066 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
7067 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
7068 * element's UpdateManager load indicator and will be destroyed after the initial load.
7070 * Create a new LoadMask
7071 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
7072 * @param {Object} config The config object
7074 Roo.LoadMask = function(el, config){
7075 this.el = Roo.get(el);
7076 Roo.apply(this, config);
7078 this.store.on('beforeload', this.onBeforeLoad, this);
7079 this.store.on('load', this.onLoad, this);
7080 this.store.on('loadexception', this.onLoadException, this);
7081 this.removeMask = false;
7083 var um = this.el.getUpdateManager();
7084 um.showLoadIndicator = false; // disable the default indicator
7085 um.on('beforeupdate', this.onBeforeLoad, this);
7086 um.on('update', this.onLoad, this);
7087 um.on('failure', this.onLoad, this);
7088 this.removeMask = true;
7092 Roo.LoadMask.prototype = {
7094 * @cfg {Boolean} removeMask
7095 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
7096 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
7100 * The text to display in a centered loading message box (defaults to 'Loading...')
7104 * @cfg {String} msgCls
7105 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
7107 msgCls : 'x-mask-loading',
7110 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
7116 * Disables the mask to prevent it from being displayed
7118 disable : function(){
7119 this.disabled = true;
7123 * Enables the mask so that it can be displayed
7125 enable : function(){
7126 this.disabled = false;
7129 onLoadException : function()
7133 if (typeof(arguments[3]) != 'undefined') {
7134 Roo.MessageBox.alert("Error loading",arguments[3]);
7138 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7139 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7146 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7151 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7155 onBeforeLoad : function(){
7157 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
7162 destroy : function(){
7164 this.store.un('beforeload', this.onBeforeLoad, this);
7165 this.store.un('load', this.onLoad, this);
7166 this.store.un('loadexception', this.onLoadException, this);
7168 var um = this.el.getUpdateManager();
7169 um.un('beforeupdate', this.onBeforeLoad, this);
7170 um.un('update', this.onLoad, this);
7171 um.un('failure', this.onLoad, this);
7182 * @class Roo.bootstrap.Table
7183 * @extends Roo.bootstrap.Component
7184 * Bootstrap Table class
7185 * @cfg {String} cls table class
7186 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
7187 * @cfg {String} bgcolor Specifies the background color for a table
7188 * @cfg {Number} border Specifies whether the table cells should have borders or not
7189 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
7190 * @cfg {Number} cellspacing Specifies the space between cells
7191 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
7192 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
7193 * @cfg {String} sortable Specifies that the table should be sortable
7194 * @cfg {String} summary Specifies a summary of the content of a table
7195 * @cfg {Number} width Specifies the width of a table
7196 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
7198 * @cfg {boolean} striped Should the rows be alternative striped
7199 * @cfg {boolean} bordered Add borders to the table
7200 * @cfg {boolean} hover Add hover highlighting
7201 * @cfg {boolean} condensed Format condensed
7202 * @cfg {boolean} responsive Format condensed
7203 * @cfg {Boolean} loadMask (true|false) default false
7204 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
7205 * @cfg {Boolean} headerShow (true|false) generate thead, default true
7206 * @cfg {Boolean} rowSelection (true|false) default false
7207 * @cfg {Boolean} cellSelection (true|false) default false
7208 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
7209 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
7210 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
7211 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
7215 * Create a new Table
7216 * @param {Object} config The config object
7219 Roo.bootstrap.Table = function(config){
7220 Roo.bootstrap.Table.superclass.constructor.call(this, config);
7225 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
7226 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
7227 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
7228 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
7230 this.sm = this.sm || {xtype: 'RowSelectionModel'};
7232 this.sm.grid = this;
7233 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
7234 this.sm = this.selModel;
7235 this.sm.xmodule = this.xmodule || false;
7238 if (this.cm && typeof(this.cm.config) == 'undefined') {
7239 this.colModel = new Roo.grid.ColumnModel(this.cm);
7240 this.cm = this.colModel;
7241 this.cm.xmodule = this.xmodule || false;
7244 this.store= Roo.factory(this.store, Roo.data);
7245 this.ds = this.store;
7246 this.ds.xmodule = this.xmodule || false;
7249 if (this.footer && this.store) {
7250 this.footer.dataSource = this.ds;
7251 this.footer = Roo.factory(this.footer);
7258 * Fires when a cell is clicked
7259 * @param {Roo.bootstrap.Table} this
7260 * @param {Roo.Element} el
7261 * @param {Number} rowIndex
7262 * @param {Number} columnIndex
7263 * @param {Roo.EventObject} e
7267 * @event celldblclick
7268 * Fires when a cell is double clicked
7269 * @param {Roo.bootstrap.Table} this
7270 * @param {Roo.Element} el
7271 * @param {Number} rowIndex
7272 * @param {Number} columnIndex
7273 * @param {Roo.EventObject} e
7275 "celldblclick" : true,
7278 * Fires when a row is clicked
7279 * @param {Roo.bootstrap.Table} this
7280 * @param {Roo.Element} el
7281 * @param {Number} rowIndex
7282 * @param {Roo.EventObject} e
7286 * @event rowdblclick
7287 * Fires when a row is double clicked
7288 * @param {Roo.bootstrap.Table} this
7289 * @param {Roo.Element} el
7290 * @param {Number} rowIndex
7291 * @param {Roo.EventObject} e
7293 "rowdblclick" : true,
7296 * Fires when a mouseover occur
7297 * @param {Roo.bootstrap.Table} this
7298 * @param {Roo.Element} el
7299 * @param {Number} rowIndex
7300 * @param {Number} columnIndex
7301 * @param {Roo.EventObject} e
7306 * Fires when a mouseout occur
7307 * @param {Roo.bootstrap.Table} this
7308 * @param {Roo.Element} el
7309 * @param {Number} rowIndex
7310 * @param {Number} columnIndex
7311 * @param {Roo.EventObject} e
7316 * Fires when a row is rendered, so you can change add a style to it.
7317 * @param {Roo.bootstrap.Table} this
7318 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
7322 * @event rowsrendered
7323 * Fires when all the rows have been rendered
7324 * @param {Roo.bootstrap.Table} this
7326 'rowsrendered' : true,
7328 * @event contextmenu
7329 * The raw contextmenu event for the entire grid.
7330 * @param {Roo.EventObject} e
7332 "contextmenu" : true,
7334 * @event rowcontextmenu
7335 * Fires when a row is right clicked
7336 * @param {Roo.bootstrap.Table} this
7337 * @param {Number} rowIndex
7338 * @param {Roo.EventObject} e
7340 "rowcontextmenu" : true,
7342 * @event cellcontextmenu
7343 * Fires when a cell is right clicked
7344 * @param {Roo.bootstrap.Table} this
7345 * @param {Number} rowIndex
7346 * @param {Number} cellIndex
7347 * @param {Roo.EventObject} e
7349 "cellcontextmenu" : true,
7351 * @event headercontextmenu
7352 * Fires when a header is right clicked
7353 * @param {Roo.bootstrap.Table} this
7354 * @param {Number} columnIndex
7355 * @param {Roo.EventObject} e
7357 "headercontextmenu" : true
7361 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
7387 rowSelection : false,
7388 cellSelection : false,
7391 // Roo.Element - the tbody
7393 // Roo.Element - thead element
7396 container: false, // used by gridpanel...
7402 auto_hide_footer : false,
7404 getAutoCreate : function()
7406 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
7413 if (this.scrollBody) {
7414 cfg.cls += ' table-body-fixed';
7417 cfg.cls += ' table-striped';
7421 cfg.cls += ' table-hover';
7423 if (this.bordered) {
7424 cfg.cls += ' table-bordered';
7426 if (this.condensed) {
7427 cfg.cls += ' table-condensed';
7429 if (this.responsive) {
7430 cfg.cls += ' table-responsive';
7434 cfg.cls+= ' ' +this.cls;
7437 // this lot should be simplifed...
7450 ].forEach(function(k) {
7458 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
7461 if(this.store || this.cm){
7462 if(this.headerShow){
7463 cfg.cn.push(this.renderHeader());
7466 cfg.cn.push(this.renderBody());
7468 if(this.footerShow){
7469 cfg.cn.push(this.renderFooter());
7471 // where does this come from?
7472 //cfg.cls+= ' TableGrid';
7475 return { cn : [ cfg ] };
7478 initEvents : function()
7480 if(!this.store || !this.cm){
7483 if (this.selModel) {
7484 this.selModel.initEvents();
7488 //Roo.log('initEvents with ds!!!!');
7490 this.mainBody = this.el.select('tbody', true).first();
7491 this.mainHead = this.el.select('thead', true).first();
7492 this.mainFoot = this.el.select('tfoot', true).first();
7498 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7499 e.on('click', _this.sort, _this);
7502 this.mainBody.on("click", this.onClick, this);
7503 this.mainBody.on("dblclick", this.onDblClick, this);
7505 // why is this done????? = it breaks dialogs??
7506 //this.parent().el.setStyle('position', 'relative');
7510 this.footer.parentId = this.id;
7511 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
7514 this.el.select('tfoot tr td').first().addClass('hide');
7519 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
7522 this.store.on('load', this.onLoad, this);
7523 this.store.on('beforeload', this.onBeforeLoad, this);
7524 this.store.on('update', this.onUpdate, this);
7525 this.store.on('add', this.onAdd, this);
7526 this.store.on("clear", this.clear, this);
7528 this.el.on("contextmenu", this.onContextMenu, this);
7530 this.mainBody.on('scroll', this.onBodyScroll, this);
7532 this.cm.on("headerchange", this.onHeaderChange, this);
7534 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
7538 onContextMenu : function(e, t)
7540 this.processEvent("contextmenu", e);
7543 processEvent : function(name, e)
7545 if (name != 'touchstart' ) {
7546 this.fireEvent(name, e);
7549 var t = e.getTarget();
7551 var cell = Roo.get(t);
7557 if(cell.findParent('tfoot', false, true)){
7561 if(cell.findParent('thead', false, true)){
7563 if(e.getTarget().nodeName.toLowerCase() != 'th'){
7564 cell = Roo.get(t).findParent('th', false, true);
7566 Roo.log("failed to find th in thead?");
7567 Roo.log(e.getTarget());
7572 var cellIndex = cell.dom.cellIndex;
7574 var ename = name == 'touchstart' ? 'click' : name;
7575 this.fireEvent("header" + ename, this, cellIndex, e);
7580 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7581 cell = Roo.get(t).findParent('td', false, true);
7583 Roo.log("failed to find th in tbody?");
7584 Roo.log(e.getTarget());
7589 var row = cell.findParent('tr', false, true);
7590 var cellIndex = cell.dom.cellIndex;
7591 var rowIndex = row.dom.rowIndex - 1;
7595 this.fireEvent("row" + name, this, rowIndex, e);
7599 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
7605 onMouseover : function(e, el)
7607 var cell = Roo.get(el);
7613 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7614 cell = cell.findParent('td', false, true);
7617 var row = cell.findParent('tr', false, true);
7618 var cellIndex = cell.dom.cellIndex;
7619 var rowIndex = row.dom.rowIndex - 1; // start from 0
7621 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
7625 onMouseout : function(e, el)
7627 var cell = Roo.get(el);
7633 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7634 cell = cell.findParent('td', false, true);
7637 var row = cell.findParent('tr', false, true);
7638 var cellIndex = cell.dom.cellIndex;
7639 var rowIndex = row.dom.rowIndex - 1; // start from 0
7641 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
7645 onClick : function(e, el)
7647 var cell = Roo.get(el);
7649 if(!cell || (!this.cellSelection && !this.rowSelection)){
7653 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7654 cell = cell.findParent('td', false, true);
7657 if(!cell || typeof(cell) == 'undefined'){
7661 var row = cell.findParent('tr', false, true);
7663 if(!row || typeof(row) == 'undefined'){
7667 var cellIndex = cell.dom.cellIndex;
7668 var rowIndex = this.getRowIndex(row);
7670 // why??? - should these not be based on SelectionModel?
7671 if(this.cellSelection){
7672 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
7675 if(this.rowSelection){
7676 this.fireEvent('rowclick', this, row, rowIndex, e);
7682 onDblClick : function(e,el)
7684 var cell = Roo.get(el);
7686 if(!cell || (!this.cellSelection && !this.rowSelection)){
7690 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7691 cell = cell.findParent('td', false, true);
7694 if(!cell || typeof(cell) == 'undefined'){
7698 var row = cell.findParent('tr', false, true);
7700 if(!row || typeof(row) == 'undefined'){
7704 var cellIndex = cell.dom.cellIndex;
7705 var rowIndex = this.getRowIndex(row);
7707 if(this.cellSelection){
7708 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
7711 if(this.rowSelection){
7712 this.fireEvent('rowdblclick', this, row, rowIndex, e);
7716 sort : function(e,el)
7718 var col = Roo.get(el);
7720 if(!col.hasClass('sortable')){
7724 var sort = col.attr('sort');
7727 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
7731 this.store.sortInfo = {field : sort, direction : dir};
7734 Roo.log("calling footer first");
7735 this.footer.onClick('first');
7738 this.store.load({ params : { start : 0 } });
7742 renderHeader : function()
7750 this.totalWidth = 0;
7752 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7754 var config = cm.config[i];
7758 cls : 'x-hcol-' + i,
7760 html: cm.getColumnHeader(i)
7765 if(typeof(config.sortable) != 'undefined' && config.sortable){
7767 c.html = '<i class="glyphicon"></i>' + c.html;
7770 // could use BS4 hidden-..-down
7772 if(typeof(config.lgHeader) != 'undefined'){
7773 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
7776 if(typeof(config.mdHeader) != 'undefined'){
7777 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
7780 if(typeof(config.smHeader) != 'undefined'){
7781 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
7784 if(typeof(config.xsHeader) != 'undefined'){
7785 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
7792 if(typeof(config.tooltip) != 'undefined'){
7793 c.tooltip = config.tooltip;
7796 if(typeof(config.colspan) != 'undefined'){
7797 c.colspan = config.colspan;
7800 if(typeof(config.hidden) != 'undefined' && config.hidden){
7801 c.style += ' display:none;';
7804 if(typeof(config.dataIndex) != 'undefined'){
7805 c.sort = config.dataIndex;
7810 if(typeof(config.align) != 'undefined' && config.align.length){
7811 c.style += ' text-align:' + config.align + ';';
7814 if(typeof(config.width) != 'undefined'){
7815 c.style += ' width:' + config.width + 'px;';
7816 this.totalWidth += config.width;
7818 this.totalWidth += 100; // assume minimum of 100 per column?
7821 if(typeof(config.cls) != 'undefined'){
7822 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
7825 ['xs','sm','md','lg'].map(function(size){
7827 if(typeof(config[size]) == 'undefined'){
7831 if (!config[size]) { // 0 = hidden
7832 // BS 4 '0' is treated as hide that column and below.
7833 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
7837 c.cls += ' col-' + size + '-' + config[size] + (
7838 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7850 renderBody : function()
7860 colspan : this.cm.getColumnCount()
7870 renderFooter : function()
7880 colspan : this.cm.getColumnCount()
7894 // Roo.log('ds onload');
7899 var ds = this.store;
7901 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7902 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
7903 if (_this.store.sortInfo) {
7905 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
7906 e.select('i', true).addClass(['glyphicon-arrow-up']);
7909 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
7910 e.select('i', true).addClass(['glyphicon-arrow-down']);
7915 var tbody = this.mainBody;
7917 if(ds.getCount() > 0){
7918 ds.data.each(function(d,rowIndex){
7919 var row = this.renderRow(cm, ds, rowIndex);
7921 tbody.createChild(row);
7925 if(row.cellObjects.length){
7926 Roo.each(row.cellObjects, function(r){
7927 _this.renderCellObject(r);
7934 var tfoot = this.el.select('tfoot', true).first();
7936 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7938 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7940 var total = this.ds.getTotalCount();
7942 if(this.footer.pageSize < total){
7943 this.mainFoot.show();
7947 Roo.each(this.el.select('tbody td', true).elements, function(e){
7948 e.on('mouseover', _this.onMouseover, _this);
7951 Roo.each(this.el.select('tbody td', true).elements, function(e){
7952 e.on('mouseout', _this.onMouseout, _this);
7954 this.fireEvent('rowsrendered', this);
7960 onUpdate : function(ds,record)
7962 this.refreshRow(record);
7966 onRemove : function(ds, record, index, isUpdate){
7967 if(isUpdate !== true){
7968 this.fireEvent("beforerowremoved", this, index, record);
7970 var bt = this.mainBody.dom;
7972 var rows = this.el.select('tbody > tr', true).elements;
7974 if(typeof(rows[index]) != 'undefined'){
7975 bt.removeChild(rows[index].dom);
7978 // if(bt.rows[index]){
7979 // bt.removeChild(bt.rows[index]);
7982 if(isUpdate !== true){
7983 //this.stripeRows(index);
7984 //this.syncRowHeights(index, index);
7986 this.fireEvent("rowremoved", this, index, record);
7990 onAdd : function(ds, records, rowIndex)
7992 //Roo.log('on Add called');
7993 // - note this does not handle multiple adding very well..
7994 var bt = this.mainBody.dom;
7995 for (var i =0 ; i < records.length;i++) {
7996 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7997 //Roo.log(records[i]);
7998 //Roo.log(this.store.getAt(rowIndex+i));
7999 this.insertRow(this.store, rowIndex + i, false);
8006 refreshRow : function(record){
8007 var ds = this.store, index;
8008 if(typeof record == 'number'){
8010 record = ds.getAt(index);
8012 index = ds.indexOf(record);
8014 this.insertRow(ds, index, true);
8016 this.onRemove(ds, record, index+1, true);
8018 //this.syncRowHeights(index, index);
8020 this.fireEvent("rowupdated", this, index, record);
8023 insertRow : function(dm, rowIndex, isUpdate){
8026 this.fireEvent("beforerowsinserted", this, rowIndex);
8028 //var s = this.getScrollState();
8029 var row = this.renderRow(this.cm, this.store, rowIndex);
8030 // insert before rowIndex..
8031 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
8035 if(row.cellObjects.length){
8036 Roo.each(row.cellObjects, function(r){
8037 _this.renderCellObject(r);
8042 this.fireEvent("rowsinserted", this, rowIndex);
8043 //this.syncRowHeights(firstRow, lastRow);
8044 //this.stripeRows(firstRow);
8051 getRowDom : function(rowIndex)
8053 var rows = this.el.select('tbody > tr', true).elements;
8055 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
8058 // returns the object tree for a tr..
8061 renderRow : function(cm, ds, rowIndex)
8063 var d = ds.getAt(rowIndex);
8067 cls : 'x-row-' + rowIndex,
8071 var cellObjects = [];
8073 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8074 var config = cm.config[i];
8076 var renderer = cm.getRenderer(i);
8080 if(typeof(renderer) !== 'undefined'){
8081 value = renderer(d.data[cm.getDataIndex(i)], false, d);
8083 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
8084 // and are rendered into the cells after the row is rendered - using the id for the element.
8086 if(typeof(value) === 'object'){
8096 rowIndex : rowIndex,
8101 this.fireEvent('rowclass', this, rowcfg);
8105 cls : rowcfg.rowClass + ' x-col-' + i,
8107 html: (typeof(value) === 'object') ? '' : value
8114 if(typeof(config.colspan) != 'undefined'){
8115 td.colspan = config.colspan;
8118 if(typeof(config.hidden) != 'undefined' && config.hidden){
8119 td.style += ' display:none;';
8122 if(typeof(config.align) != 'undefined' && config.align.length){
8123 td.style += ' text-align:' + config.align + ';';
8125 if(typeof(config.valign) != 'undefined' && config.valign.length){
8126 td.style += ' vertical-align:' + config.valign + ';';
8129 if(typeof(config.width) != 'undefined'){
8130 td.style += ' width:' + config.width + 'px;';
8133 if(typeof(config.cursor) != 'undefined'){
8134 td.style += ' cursor:' + config.cursor + ';';
8137 if(typeof(config.cls) != 'undefined'){
8138 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
8141 ['xs','sm','md','lg'].map(function(size){
8143 if(typeof(config[size]) == 'undefined'){
8149 if (!config[size]) { // 0 = hidden
8150 // BS 4 '0' is treated as hide that column and below.
8151 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
8155 td.cls += ' col-' + size + '-' + config[size] + (
8156 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8166 row.cellObjects = cellObjects;
8174 onBeforeLoad : function()
8183 this.el.select('tbody', true).first().dom.innerHTML = '';
8186 * Show or hide a row.
8187 * @param {Number} rowIndex to show or hide
8188 * @param {Boolean} state hide
8190 setRowVisibility : function(rowIndex, state)
8192 var bt = this.mainBody.dom;
8194 var rows = this.el.select('tbody > tr', true).elements;
8196 if(typeof(rows[rowIndex]) == 'undefined'){
8199 rows[rowIndex].dom.style.display = state ? '' : 'none';
8203 getSelectionModel : function(){
8205 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
8207 return this.selModel;
8210 * Render the Roo.bootstrap object from renderder
8212 renderCellObject : function(r)
8216 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
8218 var t = r.cfg.render(r.container);
8221 Roo.each(r.cfg.cn, function(c){
8223 container: t.getChildContainer(),
8226 _this.renderCellObject(child);
8231 getRowIndex : function(row)
8235 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
8246 * Returns the grid's underlying element = used by panel.Grid
8247 * @return {Element} The element
8249 getGridEl : function(){
8253 * Forces a resize - used by panel.Grid
8254 * @return {Element} The element
8256 autoSize : function()
8258 //var ctr = Roo.get(this.container.dom.parentElement);
8259 var ctr = Roo.get(this.el.dom);
8261 var thd = this.getGridEl().select('thead',true).first();
8262 var tbd = this.getGridEl().select('tbody', true).first();
8263 var tfd = this.getGridEl().select('tfoot', true).first();
8265 var cw = ctr.getWidth();
8269 tbd.setWidth(ctr.getWidth());
8270 // if the body has a max height - and then scrolls - we should perhaps set up the height here
8271 // this needs fixing for various usage - currently only hydra job advers I think..
8273 // ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
8275 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
8278 cw = Math.max(cw, this.totalWidth);
8279 this.getGridEl().select('tr',true).setWidth(cw);
8280 // resize 'expandable coloumn?
8282 return; // we doe not have a view in this design..
8285 onBodyScroll: function()
8287 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
8289 this.mainHead.setStyle({
8290 'position' : 'relative',
8291 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
8297 var scrollHeight = this.mainBody.dom.scrollHeight;
8299 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
8301 var height = this.mainBody.getHeight();
8303 if(scrollHeight - height == scrollTop) {
8305 var total = this.ds.getTotalCount();
8307 if(this.footer.cursor + this.footer.pageSize < total){
8309 this.footer.ds.load({
8311 start : this.footer.cursor + this.footer.pageSize,
8312 limit : this.footer.pageSize
8322 onHeaderChange : function()
8324 var header = this.renderHeader();
8325 var table = this.el.select('table', true).first();
8327 this.mainHead.remove();
8328 this.mainHead = table.createChild(header, this.mainBody, false);
8331 onHiddenChange : function(colModel, colIndex, hidden)
8333 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
8334 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
8336 this.CSS.updateRule(thSelector, "display", "");
8337 this.CSS.updateRule(tdSelector, "display", "");
8340 this.CSS.updateRule(thSelector, "display", "none");
8341 this.CSS.updateRule(tdSelector, "display", "none");
8344 this.onHeaderChange();
8348 setColumnWidth: function(col_index, width)
8350 // width = "md-2 xs-2..."
8351 if(!this.colModel.config[col_index]) {
8355 var w = width.split(" ");
8357 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
8359 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
8362 for(var j = 0; j < w.length; j++) {
8368 var size_cls = w[j].split("-");
8370 if(!Number.isInteger(size_cls[1] * 1)) {
8374 if(!this.colModel.config[col_index][size_cls[0]]) {
8378 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8382 h_row[0].classList.replace(
8383 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8384 "col-"+size_cls[0]+"-"+size_cls[1]
8387 for(var i = 0; i < rows.length; i++) {
8389 var size_cls = w[j].split("-");
8391 if(!Number.isInteger(size_cls[1] * 1)) {
8395 if(!this.colModel.config[col_index][size_cls[0]]) {
8399 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8403 rows[i].classList.replace(
8404 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8405 "col-"+size_cls[0]+"-"+size_cls[1]
8409 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
8424 * @class Roo.bootstrap.TableCell
8425 * @extends Roo.bootstrap.Component
8426 * Bootstrap TableCell class
8427 * @cfg {String} html cell contain text
8428 * @cfg {String} cls cell class
8429 * @cfg {String} tag cell tag (td|th) default td
8430 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
8431 * @cfg {String} align Aligns the content in a cell
8432 * @cfg {String} axis Categorizes cells
8433 * @cfg {String} bgcolor Specifies the background color of a cell
8434 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8435 * @cfg {Number} colspan Specifies the number of columns a cell should span
8436 * @cfg {String} headers Specifies one or more header cells a cell is related to
8437 * @cfg {Number} height Sets the height of a cell
8438 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
8439 * @cfg {Number} rowspan Sets the number of rows a cell should span
8440 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
8441 * @cfg {String} valign Vertical aligns the content in a cell
8442 * @cfg {Number} width Specifies the width of a cell
8445 * Create a new TableCell
8446 * @param {Object} config The config object
8449 Roo.bootstrap.TableCell = function(config){
8450 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
8453 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
8473 getAutoCreate : function(){
8474 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
8494 cfg.align=this.align
8500 cfg.bgcolor=this.bgcolor
8503 cfg.charoff=this.charoff
8506 cfg.colspan=this.colspan
8509 cfg.headers=this.headers
8512 cfg.height=this.height
8515 cfg.nowrap=this.nowrap
8518 cfg.rowspan=this.rowspan
8521 cfg.scope=this.scope
8524 cfg.valign=this.valign
8527 cfg.width=this.width
8546 * @class Roo.bootstrap.TableRow
8547 * @extends Roo.bootstrap.Component
8548 * Bootstrap TableRow class
8549 * @cfg {String} cls row class
8550 * @cfg {String} align Aligns the content in a table row
8551 * @cfg {String} bgcolor Specifies a background color for a table row
8552 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8553 * @cfg {String} valign Vertical aligns the content in a table row
8556 * Create a new TableRow
8557 * @param {Object} config The config object
8560 Roo.bootstrap.TableRow = function(config){
8561 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
8564 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
8572 getAutoCreate : function(){
8573 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
8583 cfg.align = this.align;
8586 cfg.bgcolor = this.bgcolor;
8589 cfg.charoff = this.charoff;
8592 cfg.valign = this.valign;
8610 * @class Roo.bootstrap.TableBody
8611 * @extends Roo.bootstrap.Component
8612 * Bootstrap TableBody class
8613 * @cfg {String} cls element class
8614 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
8615 * @cfg {String} align Aligns the content inside the element
8616 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
8617 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
8620 * Create a new TableBody
8621 * @param {Object} config The config object
8624 Roo.bootstrap.TableBody = function(config){
8625 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
8628 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
8636 getAutoCreate : function(){
8637 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
8651 cfg.align = this.align;
8654 cfg.charoff = this.charoff;
8657 cfg.valign = this.valign;
8664 // initEvents : function()
8671 // this.store = Roo.factory(this.store, Roo.data);
8672 // this.store.on('load', this.onLoad, this);
8674 // this.store.load();
8678 // onLoad: function ()
8680 // this.fireEvent('load', this);
8690 * Ext JS Library 1.1.1
8691 * Copyright(c) 2006-2007, Ext JS, LLC.
8693 * Originally Released Under LGPL - original licence link has changed is not relivant.
8696 * <script type="text/javascript">
8699 // as we use this in bootstrap.
8700 Roo.namespace('Roo.form');
8702 * @class Roo.form.Action
8703 * Internal Class used to handle form actions
8705 * @param {Roo.form.BasicForm} el The form element or its id
8706 * @param {Object} config Configuration options
8711 // define the action interface
8712 Roo.form.Action = function(form, options){
8714 this.options = options || {};
8717 * Client Validation Failed
8720 Roo.form.Action.CLIENT_INVALID = 'client';
8722 * Server Validation Failed
8725 Roo.form.Action.SERVER_INVALID = 'server';
8727 * Connect to Server Failed
8730 Roo.form.Action.CONNECT_FAILURE = 'connect';
8732 * Reading Data from Server Failed
8735 Roo.form.Action.LOAD_FAILURE = 'load';
8737 Roo.form.Action.prototype = {
8739 failureType : undefined,
8740 response : undefined,
8744 run : function(options){
8749 success : function(response){
8754 handleResponse : function(response){
8758 // default connection failure
8759 failure : function(response){
8761 this.response = response;
8762 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8763 this.form.afterAction(this, false);
8766 processResponse : function(response){
8767 this.response = response;
8768 if(!response.responseText){
8771 this.result = this.handleResponse(response);
8775 // utility functions used internally
8776 getUrl : function(appendParams){
8777 var url = this.options.url || this.form.url || this.form.el.dom.action;
8779 var p = this.getParams();
8781 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
8787 getMethod : function(){
8788 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
8791 getParams : function(){
8792 var bp = this.form.baseParams;
8793 var p = this.options.params;
8795 if(typeof p == "object"){
8796 p = Roo.urlEncode(Roo.applyIf(p, bp));
8797 }else if(typeof p == 'string' && bp){
8798 p += '&' + Roo.urlEncode(bp);
8801 p = Roo.urlEncode(bp);
8806 createCallback : function(){
8808 success: this.success,
8809 failure: this.failure,
8811 timeout: (this.form.timeout*1000),
8812 upload: this.form.fileUpload ? this.success : undefined
8817 Roo.form.Action.Submit = function(form, options){
8818 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
8821 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
8824 haveProgress : false,
8825 uploadComplete : false,
8827 // uploadProgress indicator.
8828 uploadProgress : function()
8830 if (!this.form.progressUrl) {
8834 if (!this.haveProgress) {
8835 Roo.MessageBox.progress("Uploading", "Uploading");
8837 if (this.uploadComplete) {
8838 Roo.MessageBox.hide();
8842 this.haveProgress = true;
8844 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
8846 var c = new Roo.data.Connection();
8848 url : this.form.progressUrl,
8853 success : function(req){
8854 //console.log(data);
8858 rdata = Roo.decode(req.responseText)
8860 Roo.log("Invalid data from server..");
8864 if (!rdata || !rdata.success) {
8866 Roo.MessageBox.alert(Roo.encode(rdata));
8869 var data = rdata.data;
8871 if (this.uploadComplete) {
8872 Roo.MessageBox.hide();
8877 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
8878 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
8881 this.uploadProgress.defer(2000,this);
8884 failure: function(data) {
8885 Roo.log('progress url failed ');
8896 // run get Values on the form, so it syncs any secondary forms.
8897 this.form.getValues();
8899 var o = this.options;
8900 var method = this.getMethod();
8901 var isPost = method == 'POST';
8902 if(o.clientValidation === false || this.form.isValid()){
8904 if (this.form.progressUrl) {
8905 this.form.findField('UPLOAD_IDENTIFIER').setValue(
8906 (new Date() * 1) + '' + Math.random());
8911 Roo.Ajax.request(Roo.apply(this.createCallback(), {
8912 form:this.form.el.dom,
8913 url:this.getUrl(!isPost),
8915 params:isPost ? this.getParams() : null,
8916 isUpload: this.form.fileUpload,
8917 formData : this.form.formData
8920 this.uploadProgress();
8922 }else if (o.clientValidation !== false){ // client validation failed
8923 this.failureType = Roo.form.Action.CLIENT_INVALID;
8924 this.form.afterAction(this, false);
8928 success : function(response)
8930 this.uploadComplete= true;
8931 if (this.haveProgress) {
8932 Roo.MessageBox.hide();
8936 var result = this.processResponse(response);
8937 if(result === true || result.success){
8938 this.form.afterAction(this, true);
8942 this.form.markInvalid(result.errors);
8943 this.failureType = Roo.form.Action.SERVER_INVALID;
8945 this.form.afterAction(this, false);
8947 failure : function(response)
8949 this.uploadComplete= true;
8950 if (this.haveProgress) {
8951 Roo.MessageBox.hide();
8954 this.response = response;
8955 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8956 this.form.afterAction(this, false);
8959 handleResponse : function(response){
8960 if(this.form.errorReader){
8961 var rs = this.form.errorReader.read(response);
8964 for(var i = 0, len = rs.records.length; i < len; i++) {
8965 var r = rs.records[i];
8969 if(errors.length < 1){
8973 success : rs.success,
8979 ret = Roo.decode(response.responseText);
8983 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8993 Roo.form.Action.Load = function(form, options){
8994 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8995 this.reader = this.form.reader;
8998 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
9003 Roo.Ajax.request(Roo.apply(
9004 this.createCallback(), {
9005 method:this.getMethod(),
9006 url:this.getUrl(false),
9007 params:this.getParams()
9011 success : function(response){
9013 var result = this.processResponse(response);
9014 if(result === true || !result.success || !result.data){
9015 this.failureType = Roo.form.Action.LOAD_FAILURE;
9016 this.form.afterAction(this, false);
9019 this.form.clearInvalid();
9020 this.form.setValues(result.data);
9021 this.form.afterAction(this, true);
9024 handleResponse : function(response){
9025 if(this.form.reader){
9026 var rs = this.form.reader.read(response);
9027 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
9029 success : rs.success,
9033 return Roo.decode(response.responseText);
9037 Roo.form.Action.ACTION_TYPES = {
9038 'load' : Roo.form.Action.Load,
9039 'submit' : Roo.form.Action.Submit
9048 * @class Roo.bootstrap.Form
9049 * @extends Roo.bootstrap.Component
9050 * Bootstrap Form class
9051 * @cfg {String} method GET | POST (default POST)
9052 * @cfg {String} labelAlign top | left (default top)
9053 * @cfg {String} align left | right - for navbars
9054 * @cfg {Boolean} loadMask load mask when submit (default true)
9059 * @param {Object} config The config object
9063 Roo.bootstrap.Form = function(config){
9065 Roo.bootstrap.Form.superclass.constructor.call(this, config);
9067 Roo.bootstrap.Form.popover.apply();
9071 * @event clientvalidation
9072 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
9073 * @param {Form} this
9074 * @param {Boolean} valid true if the form has passed client-side validation
9076 clientvalidation: true,
9078 * @event beforeaction
9079 * Fires before any action is performed. Return false to cancel the action.
9080 * @param {Form} this
9081 * @param {Action} action The action to be performed
9085 * @event actionfailed
9086 * Fires when an action fails.
9087 * @param {Form} this
9088 * @param {Action} action The action that failed
9090 actionfailed : true,
9092 * @event actioncomplete
9093 * Fires when an action is completed.
9094 * @param {Form} this
9095 * @param {Action} action The action that completed
9097 actioncomplete : true
9101 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
9104 * @cfg {String} method
9105 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
9110 * The URL to use for form actions if one isn't supplied in the action options.
9113 * @cfg {Boolean} fileUpload
9114 * Set to true if this form is a file upload.
9118 * @cfg {Object} baseParams
9119 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
9123 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
9127 * @cfg {Sting} align (left|right) for navbar forms
9132 activeAction : null,
9135 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
9136 * element by passing it or its id or mask the form itself by passing in true.
9139 waitMsgTarget : false,
9144 * @cfg {Boolean} errorMask (true|false) default false
9149 * @cfg {Number} maskOffset Default 100
9154 * @cfg {Boolean} maskBody
9158 getAutoCreate : function(){
9162 method : this.method || 'POST',
9163 id : this.id || Roo.id(),
9166 if (this.parent().xtype.match(/^Nav/)) {
9167 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
9171 if (this.labelAlign == 'left' ) {
9172 cfg.cls += ' form-horizontal';
9178 initEvents : function()
9180 this.el.on('submit', this.onSubmit, this);
9181 // this was added as random key presses on the form where triggering form submit.
9182 this.el.on('keypress', function(e) {
9183 if (e.getCharCode() != 13) {
9186 // we might need to allow it for textareas.. and some other items.
9187 // check e.getTarget().
9189 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
9193 Roo.log("keypress blocked");
9201 onSubmit : function(e){
9206 * Returns true if client-side validation on the form is successful.
9209 isValid : function(){
9210 var items = this.getItems();
9214 items.each(function(f){
9220 Roo.log('invalid field: ' + f.name);
9224 if(!target && f.el.isVisible(true)){
9230 if(this.errorMask && !valid){
9231 Roo.bootstrap.Form.popover.mask(this, target);
9238 * Returns true if any fields in this form have changed since their original load.
9241 isDirty : function(){
9243 var items = this.getItems();
9244 items.each(function(f){
9254 * Performs a predefined action (submit or load) or custom actions you define on this form.
9255 * @param {String} actionName The name of the action type
9256 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
9257 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
9258 * accept other config options):
9260 Property Type Description
9261 ---------------- --------------- ----------------------------------------------------------------------------------
9262 url String The url for the action (defaults to the form's url)
9263 method String The form method to use (defaults to the form's method, or POST if not defined)
9264 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
9265 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
9266 validate the form on the client (defaults to false)
9268 * @return {BasicForm} this
9270 doAction : function(action, options){
9271 if(typeof action == 'string'){
9272 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
9274 if(this.fireEvent('beforeaction', this, action) !== false){
9275 this.beforeAction(action);
9276 action.run.defer(100, action);
9282 beforeAction : function(action){
9283 var o = action.options;
9288 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
9290 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9293 // not really supported yet.. ??
9295 //if(this.waitMsgTarget === true){
9296 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9297 //}else if(this.waitMsgTarget){
9298 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
9299 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
9301 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
9307 afterAction : function(action, success){
9308 this.activeAction = null;
9309 var o = action.options;
9314 Roo.get(document.body).unmask();
9320 //if(this.waitMsgTarget === true){
9321 // this.el.unmask();
9322 //}else if(this.waitMsgTarget){
9323 // this.waitMsgTarget.unmask();
9325 // Roo.MessageBox.updateProgress(1);
9326 // Roo.MessageBox.hide();
9333 Roo.callback(o.success, o.scope, [this, action]);
9334 this.fireEvent('actioncomplete', this, action);
9338 // failure condition..
9339 // we have a scenario where updates need confirming.
9340 // eg. if a locking scenario exists..
9341 // we look for { errors : { needs_confirm : true }} in the response.
9343 (typeof(action.result) != 'undefined') &&
9344 (typeof(action.result.errors) != 'undefined') &&
9345 (typeof(action.result.errors.needs_confirm) != 'undefined')
9348 Roo.log("not supported yet");
9351 Roo.MessageBox.confirm(
9352 "Change requires confirmation",
9353 action.result.errorMsg,
9358 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
9368 Roo.callback(o.failure, o.scope, [this, action]);
9369 // show an error message if no failed handler is set..
9370 if (!this.hasListener('actionfailed')) {
9371 Roo.log("need to add dialog support");
9373 Roo.MessageBox.alert("Error",
9374 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
9375 action.result.errorMsg :
9376 "Saving Failed, please check your entries or try again"
9381 this.fireEvent('actionfailed', this, action);
9386 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
9387 * @param {String} id The value to search for
9390 findField : function(id){
9391 var items = this.getItems();
9392 var field = items.get(id);
9394 items.each(function(f){
9395 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
9402 return field || null;
9405 * Mark fields in this form invalid in bulk.
9406 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
9407 * @return {BasicForm} this
9409 markInvalid : function(errors){
9410 if(errors instanceof Array){
9411 for(var i = 0, len = errors.length; i < len; i++){
9412 var fieldError = errors[i];
9413 var f = this.findField(fieldError.id);
9415 f.markInvalid(fieldError.msg);
9421 if(typeof errors[id] != 'function' && (field = this.findField(id))){
9422 field.markInvalid(errors[id]);
9426 //Roo.each(this.childForms || [], function (f) {
9427 // f.markInvalid(errors);
9434 * Set values for fields in this form in bulk.
9435 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
9436 * @return {BasicForm} this
9438 setValues : function(values){
9439 if(values instanceof Array){ // array of objects
9440 for(var i = 0, len = values.length; i < len; i++){
9442 var f = this.findField(v.id);
9444 f.setValue(v.value);
9445 if(this.trackResetOnLoad){
9446 f.originalValue = f.getValue();
9450 }else{ // object hash
9453 if(typeof values[id] != 'function' && (field = this.findField(id))){
9455 if (field.setFromData &&
9457 field.displayField &&
9458 // combos' with local stores can
9459 // be queried via setValue()
9460 // to set their value..
9461 (field.store && !field.store.isLocal)
9465 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
9466 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
9467 field.setFromData(sd);
9469 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
9471 field.setFromData(values);
9474 field.setValue(values[id]);
9478 if(this.trackResetOnLoad){
9479 field.originalValue = field.getValue();
9485 //Roo.each(this.childForms || [], function (f) {
9486 // f.setValues(values);
9493 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
9494 * they are returned as an array.
9495 * @param {Boolean} asString
9498 getValues : function(asString){
9499 //if (this.childForms) {
9500 // copy values from the child forms
9501 // Roo.each(this.childForms, function (f) {
9502 // this.setValues(f.getValues());
9508 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
9509 if(asString === true){
9512 return Roo.urlDecode(fs);
9516 * Returns the fields in this form as an object with key/value pairs.
9517 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
9520 getFieldValues : function(with_hidden)
9522 var items = this.getItems();
9524 items.each(function(f){
9530 var v = f.getValue();
9532 if (f.inputType =='radio') {
9533 if (typeof(ret[f.getName()]) == 'undefined') {
9534 ret[f.getName()] = ''; // empty..
9537 if (!f.el.dom.checked) {
9545 if(f.xtype == 'MoneyField'){
9546 ret[f.currencyName] = f.getCurrency();
9549 // not sure if this supported any more..
9550 if ((typeof(v) == 'object') && f.getRawValue) {
9551 v = f.getRawValue() ; // dates..
9553 // combo boxes where name != hiddenName...
9554 if (f.name !== false && f.name != '' && f.name != f.getName()) {
9555 ret[f.name] = f.getRawValue();
9557 ret[f.getName()] = v;
9564 * Clears all invalid messages in this form.
9565 * @return {BasicForm} this
9567 clearInvalid : function(){
9568 var items = this.getItems();
9570 items.each(function(f){
9579 * @return {BasicForm} this
9582 var items = this.getItems();
9583 items.each(function(f){
9587 Roo.each(this.childForms || [], function (f) {
9595 getItems : function()
9597 var r=new Roo.util.MixedCollection(false, function(o){
9598 return o.id || (o.id = Roo.id());
9600 var iter = function(el) {
9607 Roo.each(el.items,function(e) {
9616 hideFields : function(items)
9618 Roo.each(items, function(i){
9620 var f = this.findField(i);
9631 showFields : function(items)
9633 Roo.each(items, function(i){
9635 var f = this.findField(i);
9648 Roo.apply(Roo.bootstrap.Form, {
9675 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
9676 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
9677 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
9678 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
9681 this.maskEl.top.enableDisplayMode("block");
9682 this.maskEl.left.enableDisplayMode("block");
9683 this.maskEl.bottom.enableDisplayMode("block");
9684 this.maskEl.right.enableDisplayMode("block");
9686 this.toolTip = new Roo.bootstrap.Tooltip({
9687 cls : 'roo-form-error-popover',
9689 'left' : ['r-l', [-2,0], 'right'],
9690 'right' : ['l-r', [2,0], 'left'],
9691 'bottom' : ['tl-bl', [0,2], 'top'],
9692 'top' : [ 'bl-tl', [0,-2], 'bottom']
9696 this.toolTip.render(Roo.get(document.body));
9698 this.toolTip.el.enableDisplayMode("block");
9700 Roo.get(document.body).on('click', function(){
9704 Roo.get(document.body).on('touchstart', function(){
9708 this.isApplied = true
9711 mask : function(form, target)
9715 this.target = target;
9717 if(!this.form.errorMask || !target.el){
9721 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
9723 Roo.log(scrollable);
9725 var ot = this.target.el.calcOffsetsTo(scrollable);
9727 var scrollTo = ot[1] - this.form.maskOffset;
9729 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
9731 scrollable.scrollTo('top', scrollTo);
9733 var box = this.target.el.getBox();
9735 var zIndex = Roo.bootstrap.Modal.zIndex++;
9738 this.maskEl.top.setStyle('position', 'absolute');
9739 this.maskEl.top.setStyle('z-index', zIndex);
9740 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
9741 this.maskEl.top.setLeft(0);
9742 this.maskEl.top.setTop(0);
9743 this.maskEl.top.show();
9745 this.maskEl.left.setStyle('position', 'absolute');
9746 this.maskEl.left.setStyle('z-index', zIndex);
9747 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
9748 this.maskEl.left.setLeft(0);
9749 this.maskEl.left.setTop(box.y - this.padding);
9750 this.maskEl.left.show();
9752 this.maskEl.bottom.setStyle('position', 'absolute');
9753 this.maskEl.bottom.setStyle('z-index', zIndex);
9754 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
9755 this.maskEl.bottom.setLeft(0);
9756 this.maskEl.bottom.setTop(box.bottom + this.padding);
9757 this.maskEl.bottom.show();
9759 this.maskEl.right.setStyle('position', 'absolute');
9760 this.maskEl.right.setStyle('z-index', zIndex);
9761 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
9762 this.maskEl.right.setLeft(box.right + this.padding);
9763 this.maskEl.right.setTop(box.y - this.padding);
9764 this.maskEl.right.show();
9766 this.toolTip.bindEl = this.target.el;
9768 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
9770 var tip = this.target.blankText;
9772 if(this.target.getValue() !== '' ) {
9774 if (this.target.invalidText.length) {
9775 tip = this.target.invalidText;
9776 } else if (this.target.regexText.length){
9777 tip = this.target.regexText;
9781 this.toolTip.show(tip);
9783 this.intervalID = window.setInterval(function() {
9784 Roo.bootstrap.Form.popover.unmask();
9787 window.onwheel = function(){ return false;};
9789 (function(){ this.isMasked = true; }).defer(500, this);
9795 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
9799 this.maskEl.top.setStyle('position', 'absolute');
9800 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
9801 this.maskEl.top.hide();
9803 this.maskEl.left.setStyle('position', 'absolute');
9804 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
9805 this.maskEl.left.hide();
9807 this.maskEl.bottom.setStyle('position', 'absolute');
9808 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
9809 this.maskEl.bottom.hide();
9811 this.maskEl.right.setStyle('position', 'absolute');
9812 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
9813 this.maskEl.right.hide();
9815 this.toolTip.hide();
9817 this.toolTip.el.hide();
9819 window.onwheel = function(){ return true;};
9821 if(this.intervalID){
9822 window.clearInterval(this.intervalID);
9823 this.intervalID = false;
9826 this.isMasked = false;
9836 * Ext JS Library 1.1.1
9837 * Copyright(c) 2006-2007, Ext JS, LLC.
9839 * Originally Released Under LGPL - original licence link has changed is not relivant.
9842 * <script type="text/javascript">
9845 * @class Roo.form.VTypes
9846 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
9849 Roo.form.VTypes = function(){
9850 // closure these in so they are only created once.
9851 var alpha = /^[a-zA-Z_]+$/;
9852 var alphanum = /^[a-zA-Z0-9_]+$/;
9853 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
9854 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
9856 // All these messages and functions are configurable
9859 * The function used to validate email addresses
9860 * @param {String} value The email address
9862 'email' : function(v){
9863 return email.test(v);
9866 * The error text to display when the email validation function returns false
9869 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
9871 * The keystroke filter mask to be applied on email input
9874 'emailMask' : /[a-z0-9_\.\-@]/i,
9877 * The function used to validate URLs
9878 * @param {String} value The URL
9880 'url' : function(v){
9884 * The error text to display when the url validation function returns false
9887 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
9890 * The function used to validate alpha values
9891 * @param {String} value The value
9893 'alpha' : function(v){
9894 return alpha.test(v);
9897 * The error text to display when the alpha validation function returns false
9900 'alphaText' : 'This field should only contain letters and _',
9902 * The keystroke filter mask to be applied on alpha input
9905 'alphaMask' : /[a-z_]/i,
9908 * The function used to validate alphanumeric values
9909 * @param {String} value The value
9911 'alphanum' : function(v){
9912 return alphanum.test(v);
9915 * The error text to display when the alphanumeric validation function returns false
9918 'alphanumText' : 'This field should only contain letters, numbers and _',
9920 * The keystroke filter mask to be applied on alphanumeric input
9923 'alphanumMask' : /[a-z0-9_]/i
9933 * @class Roo.bootstrap.Input
9934 * @extends Roo.bootstrap.Component
9935 * Bootstrap Input class
9936 * @cfg {Boolean} disabled is it disabled
9937 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9938 * @cfg {String} name name of the input
9939 * @cfg {string} fieldLabel - the label associated
9940 * @cfg {string} placeholder - placeholder to put in text.
9941 * @cfg {string} before - input group add on before
9942 * @cfg {string} after - input group add on after
9943 * @cfg {string} size - (lg|sm) or leave empty..
9944 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9945 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9946 * @cfg {Number} md colspan out of 12 for computer-sized screens
9947 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9948 * @cfg {string} value default value of the input
9949 * @cfg {Number} labelWidth set the width of label
9950 * @cfg {Number} labellg set the width of label (1-12)
9951 * @cfg {Number} labelmd set the width of label (1-12)
9952 * @cfg {Number} labelsm set the width of label (1-12)
9953 * @cfg {Number} labelxs set the width of label (1-12)
9954 * @cfg {String} labelAlign (top|left)
9955 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9956 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9957 * @cfg {String} indicatorpos (left|right) default left
9958 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9959 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9961 * @cfg {String} align (left|center|right) Default left
9962 * @cfg {Boolean} forceFeedback (true|false) Default false
9965 * Create a new Input
9966 * @param {Object} config The config object
9969 Roo.bootstrap.Input = function(config){
9971 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9976 * Fires when this field receives input focus.
9977 * @param {Roo.form.Field} this
9982 * Fires when this field loses input focus.
9983 * @param {Roo.form.Field} this
9988 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9989 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9990 * @param {Roo.form.Field} this
9991 * @param {Roo.EventObject} e The event object
9996 * Fires just before the field blurs if the field value has changed.
9997 * @param {Roo.form.Field} this
9998 * @param {Mixed} newValue The new value
9999 * @param {Mixed} oldValue The original value
10004 * Fires after the field has been marked as invalid.
10005 * @param {Roo.form.Field} this
10006 * @param {String} msg The validation message
10011 * Fires after the field has been validated with no errors.
10012 * @param {Roo.form.Field} this
10017 * Fires after the key up
10018 * @param {Roo.form.Field} this
10019 * @param {Roo.EventObject} e The event Object
10025 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
10027 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
10028 automatic validation (defaults to "keyup").
10030 validationEvent : "keyup",
10032 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
10034 validateOnBlur : true,
10036 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
10038 validationDelay : 250,
10040 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
10042 focusClass : "x-form-focus", // not needed???
10046 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10048 invalidClass : "has-warning",
10051 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10053 validClass : "has-success",
10056 * @cfg {Boolean} hasFeedback (true|false) default true
10058 hasFeedback : true,
10061 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10063 invalidFeedbackClass : "glyphicon-warning-sign",
10066 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10068 validFeedbackClass : "glyphicon-ok",
10071 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
10073 selectOnFocus : false,
10076 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
10080 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
10085 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
10087 disableKeyFilter : false,
10090 * @cfg {Boolean} disabled True to disable the field (defaults to false).
10094 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
10098 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
10100 blankText : "Please complete this mandatory field",
10103 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
10107 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
10109 maxLength : Number.MAX_VALUE,
10111 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
10113 minLengthText : "The minimum length for this field is {0}",
10115 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
10117 maxLengthText : "The maximum length for this field is {0}",
10121 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
10122 * If available, this function will be called only after the basic validators all return true, and will be passed the
10123 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
10127 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
10128 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
10129 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
10133 * @cfg {String} regexText -- Depricated - use Invalid Text
10138 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
10144 autocomplete: false,
10148 inputType : 'text',
10151 placeholder: false,
10156 preventMark: false,
10157 isFormField : true,
10160 labelAlign : false,
10163 formatedValue : false,
10164 forceFeedback : false,
10166 indicatorpos : 'left',
10176 parentLabelAlign : function()
10179 while (parent.parent()) {
10180 parent = parent.parent();
10181 if (typeof(parent.labelAlign) !='undefined') {
10182 return parent.labelAlign;
10189 getAutoCreate : function()
10191 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10197 if(this.inputType != 'hidden'){
10198 cfg.cls = 'form-group' //input-group
10204 type : this.inputType,
10205 value : this.value,
10206 cls : 'form-control',
10207 placeholder : this.placeholder || '',
10208 autocomplete : this.autocomplete || 'new-password'
10211 if(this.capture.length){
10212 input.capture = this.capture;
10215 if(this.accept.length){
10216 input.accept = this.accept + "/*";
10220 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
10223 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10224 input.maxLength = this.maxLength;
10227 if (this.disabled) {
10228 input.disabled=true;
10231 if (this.readOnly) {
10232 input.readonly=true;
10236 input.name = this.name;
10240 input.cls += ' input-' + this.size;
10244 ['xs','sm','md','lg'].map(function(size){
10245 if (settings[size]) {
10246 cfg.cls += ' col-' + size + '-' + settings[size];
10250 var inputblock = input;
10254 cls: 'glyphicon form-control-feedback'
10257 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10260 cls : 'has-feedback',
10268 if (this.before || this.after) {
10271 cls : 'input-group',
10275 if (this.before && typeof(this.before) == 'string') {
10277 inputblock.cn.push({
10279 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
10283 if (this.before && typeof(this.before) == 'object') {
10284 this.before = Roo.factory(this.before);
10286 inputblock.cn.push({
10288 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
10289 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10293 inputblock.cn.push(input);
10295 if (this.after && typeof(this.after) == 'string') {
10296 inputblock.cn.push({
10298 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
10302 if (this.after && typeof(this.after) == 'object') {
10303 this.after = Roo.factory(this.after);
10305 inputblock.cn.push({
10307 cls : 'roo-input-after input-group-append input-group-text input-group-' +
10308 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10312 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10313 inputblock.cls += ' has-feedback';
10314 inputblock.cn.push(feedback);
10319 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10320 tooltip : 'This field is required'
10322 if (Roo.bootstrap.version == 4) {
10325 style : 'display-none'
10328 if (align ==='left' && this.fieldLabel.length) {
10330 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10337 cls : 'control-label col-form-label',
10338 html : this.fieldLabel
10349 var labelCfg = cfg.cn[1];
10350 var contentCfg = cfg.cn[2];
10352 if(this.indicatorpos == 'right'){
10357 cls : 'control-label col-form-label',
10361 html : this.fieldLabel
10375 labelCfg = cfg.cn[0];
10376 contentCfg = cfg.cn[1];
10380 if(this.labelWidth > 12){
10381 labelCfg.style = "width: " + this.labelWidth + 'px';
10384 if(this.labelWidth < 13 && this.labelmd == 0){
10385 this.labelmd = this.labelWidth;
10388 if(this.labellg > 0){
10389 labelCfg.cls += ' col-lg-' + this.labellg;
10390 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10393 if(this.labelmd > 0){
10394 labelCfg.cls += ' col-md-' + this.labelmd;
10395 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10398 if(this.labelsm > 0){
10399 labelCfg.cls += ' col-sm-' + this.labelsm;
10400 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10403 if(this.labelxs > 0){
10404 labelCfg.cls += ' col-xs-' + this.labelxs;
10405 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10409 } else if ( this.fieldLabel.length) {
10414 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10415 tooltip : 'This field is required'
10419 //cls : 'input-group-addon',
10420 html : this.fieldLabel
10428 if(this.indicatorpos == 'right'){
10433 //cls : 'input-group-addon',
10434 html : this.fieldLabel
10439 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10440 tooltip : 'This field is required'
10460 if (this.parentType === 'Navbar' && this.parent().bar) {
10461 cfg.cls += ' navbar-form';
10464 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
10465 // on BS4 we do this only if not form
10466 cfg.cls += ' navbar-form';
10474 * return the real input element.
10476 inputEl: function ()
10478 return this.el.select('input.form-control',true).first();
10481 tooltipEl : function()
10483 return this.inputEl();
10486 indicatorEl : function()
10488 if (Roo.bootstrap.version == 4) {
10489 return false; // not enabled in v4 yet.
10492 var indicator = this.el.select('i.roo-required-indicator',true).first();
10502 setDisabled : function(v)
10504 var i = this.inputEl().dom;
10506 i.removeAttribute('disabled');
10510 i.setAttribute('disabled','true');
10512 initEvents : function()
10515 this.inputEl().on("keydown" , this.fireKey, this);
10516 this.inputEl().on("focus", this.onFocus, this);
10517 this.inputEl().on("blur", this.onBlur, this);
10519 this.inputEl().relayEvent('keyup', this);
10521 this.indicator = this.indicatorEl();
10523 if(this.indicator){
10524 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
10527 // reference to original value for reset
10528 this.originalValue = this.getValue();
10529 //Roo.form.TextField.superclass.initEvents.call(this);
10530 if(this.validationEvent == 'keyup'){
10531 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
10532 this.inputEl().on('keyup', this.filterValidation, this);
10534 else if(this.validationEvent !== false){
10535 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
10538 if(this.selectOnFocus){
10539 this.on("focus", this.preFocus, this);
10542 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
10543 this.inputEl().on("keypress", this.filterKeys, this);
10545 this.inputEl().relayEvent('keypress', this);
10548 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
10549 this.el.on("click", this.autoSize, this);
10552 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
10553 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
10556 if (typeof(this.before) == 'object') {
10557 this.before.render(this.el.select('.roo-input-before',true).first());
10559 if (typeof(this.after) == 'object') {
10560 this.after.render(this.el.select('.roo-input-after',true).first());
10563 this.inputEl().on('change', this.onChange, this);
10566 filterValidation : function(e){
10567 if(!e.isNavKeyPress()){
10568 this.validationTask.delay(this.validationDelay);
10572 * Validates the field value
10573 * @return {Boolean} True if the value is valid, else false
10575 validate : function(){
10576 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
10577 if(this.disabled || this.validateValue(this.getRawValue())){
10582 this.markInvalid();
10588 * Validates a value according to the field's validation rules and marks the field as invalid
10589 * if the validation fails
10590 * @param {Mixed} value The value to validate
10591 * @return {Boolean} True if the value is valid, else false
10593 validateValue : function(value)
10595 if(this.getVisibilityEl().hasClass('hidden')){
10599 if(value.length < 1) { // if it's blank
10600 if(this.allowBlank){
10606 if(value.length < this.minLength){
10609 if(value.length > this.maxLength){
10613 var vt = Roo.form.VTypes;
10614 if(!vt[this.vtype](value, this)){
10618 if(typeof this.validator == "function"){
10619 var msg = this.validator(value);
10623 if (typeof(msg) == 'string') {
10624 this.invalidText = msg;
10628 if(this.regex && !this.regex.test(value)){
10636 fireKey : function(e){
10637 //Roo.log('field ' + e.getKey());
10638 if(e.isNavKeyPress()){
10639 this.fireEvent("specialkey", this, e);
10642 focus : function (selectText){
10644 this.inputEl().focus();
10645 if(selectText === true){
10646 this.inputEl().dom.select();
10652 onFocus : function(){
10653 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
10654 // this.el.addClass(this.focusClass);
10656 if(!this.hasFocus){
10657 this.hasFocus = true;
10658 this.startValue = this.getValue();
10659 this.fireEvent("focus", this);
10663 beforeBlur : Roo.emptyFn,
10667 onBlur : function(){
10669 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
10670 //this.el.removeClass(this.focusClass);
10672 this.hasFocus = false;
10673 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
10676 var v = this.getValue();
10677 if(String(v) !== String(this.startValue)){
10678 this.fireEvent('change', this, v, this.startValue);
10680 this.fireEvent("blur", this);
10683 onChange : function(e)
10685 var v = this.getValue();
10686 if(String(v) !== String(this.startValue)){
10687 this.fireEvent('change', this, v, this.startValue);
10693 * Resets the current field value to the originally loaded value and clears any validation messages
10695 reset : function(){
10696 this.setValue(this.originalValue);
10700 * Returns the name of the field
10701 * @return {Mixed} name The name field
10703 getName: function(){
10707 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
10708 * @return {Mixed} value The field value
10710 getValue : function(){
10712 var v = this.inputEl().getValue();
10717 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
10718 * @return {Mixed} value The field value
10720 getRawValue : function(){
10721 var v = this.inputEl().getValue();
10727 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
10728 * @param {Mixed} value The value to set
10730 setRawValue : function(v){
10731 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
10734 selectText : function(start, end){
10735 var v = this.getRawValue();
10737 start = start === undefined ? 0 : start;
10738 end = end === undefined ? v.length : end;
10739 var d = this.inputEl().dom;
10740 if(d.setSelectionRange){
10741 d.setSelectionRange(start, end);
10742 }else if(d.createTextRange){
10743 var range = d.createTextRange();
10744 range.moveStart("character", start);
10745 range.moveEnd("character", v.length-end);
10752 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
10753 * @param {Mixed} value The value to set
10755 setValue : function(v){
10758 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
10764 processValue : function(value){
10765 if(this.stripCharsRe){
10766 var newValue = value.replace(this.stripCharsRe, '');
10767 if(newValue !== value){
10768 this.setRawValue(newValue);
10775 preFocus : function(){
10777 if(this.selectOnFocus){
10778 this.inputEl().dom.select();
10781 filterKeys : function(e){
10782 var k = e.getKey();
10783 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
10786 var c = e.getCharCode(), cc = String.fromCharCode(c);
10787 if(Roo.isIE && (e.isSpecialKey() || !cc)){
10790 if(!this.maskRe.test(cc)){
10795 * Clear any invalid styles/messages for this field
10797 clearInvalid : function(){
10799 if(!this.el || this.preventMark){ // not rendered
10804 this.el.removeClass([this.invalidClass, 'is-invalid']);
10806 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10808 var feedback = this.el.select('.form-control-feedback', true).first();
10811 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10816 if(this.indicator){
10817 this.indicator.removeClass('visible');
10818 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10821 this.fireEvent('valid', this);
10825 * Mark this field as valid
10827 markValid : function()
10829 if(!this.el || this.preventMark){ // not rendered...
10833 this.el.removeClass([this.invalidClass, this.validClass]);
10834 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10836 var feedback = this.el.select('.form-control-feedback', true).first();
10839 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10842 if(this.indicator){
10843 this.indicator.removeClass('visible');
10844 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10851 if(this.allowBlank && !this.getRawValue().length){
10854 if (Roo.bootstrap.version == 3) {
10855 this.el.addClass(this.validClass);
10857 this.inputEl().addClass('is-valid');
10860 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10862 var feedback = this.el.select('.form-control-feedback', true).first();
10865 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10866 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10871 this.fireEvent('valid', this);
10875 * Mark this field as invalid
10876 * @param {String} msg The validation message
10878 markInvalid : function(msg)
10880 if(!this.el || this.preventMark){ // not rendered
10884 this.el.removeClass([this.invalidClass, this.validClass]);
10885 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10887 var feedback = this.el.select('.form-control-feedback', true).first();
10890 this.el.select('.form-control-feedback', true).first().removeClass(
10891 [this.invalidFeedbackClass, this.validFeedbackClass]);
10898 if(this.allowBlank && !this.getRawValue().length){
10902 if(this.indicator){
10903 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10904 this.indicator.addClass('visible');
10906 if (Roo.bootstrap.version == 3) {
10907 this.el.addClass(this.invalidClass);
10909 this.inputEl().addClass('is-invalid');
10914 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10916 var feedback = this.el.select('.form-control-feedback', true).first();
10919 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10921 if(this.getValue().length || this.forceFeedback){
10922 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10929 this.fireEvent('invalid', this, msg);
10932 SafariOnKeyDown : function(event)
10934 // this is a workaround for a password hang bug on chrome/ webkit.
10935 if (this.inputEl().dom.type != 'password') {
10939 var isSelectAll = false;
10941 if(this.inputEl().dom.selectionEnd > 0){
10942 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10944 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10945 event.preventDefault();
10950 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10952 event.preventDefault();
10953 // this is very hacky as keydown always get's upper case.
10955 var cc = String.fromCharCode(event.getCharCode());
10956 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10960 adjustWidth : function(tag, w){
10961 tag = tag.toLowerCase();
10962 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10963 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10964 if(tag == 'input'){
10967 if(tag == 'textarea'){
10970 }else if(Roo.isOpera){
10971 if(tag == 'input'){
10974 if(tag == 'textarea'){
10982 setFieldLabel : function(v)
10984 if(!this.rendered){
10988 if(this.indicatorEl()){
10989 var ar = this.el.select('label > span',true);
10991 if (ar.elements.length) {
10992 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10993 this.fieldLabel = v;
10997 var br = this.el.select('label',true);
10999 if(br.elements.length) {
11000 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11001 this.fieldLabel = v;
11005 Roo.log('Cannot Found any of label > span || label in input');
11009 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11010 this.fieldLabel = v;
11025 * @class Roo.bootstrap.TextArea
11026 * @extends Roo.bootstrap.Input
11027 * Bootstrap TextArea class
11028 * @cfg {Number} cols Specifies the visible width of a text area
11029 * @cfg {Number} rows Specifies the visible number of lines in a text area
11030 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
11031 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
11032 * @cfg {string} html text
11035 * Create a new TextArea
11036 * @param {Object} config The config object
11039 Roo.bootstrap.TextArea = function(config){
11040 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
11044 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
11054 getAutoCreate : function(){
11056 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11062 if(this.inputType != 'hidden'){
11063 cfg.cls = 'form-group' //input-group
11071 value : this.value || '',
11072 html: this.html || '',
11073 cls : 'form-control',
11074 placeholder : this.placeholder || ''
11078 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
11079 input.maxLength = this.maxLength;
11083 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
11087 input.cols = this.cols;
11090 if (this.readOnly) {
11091 input.readonly = true;
11095 input.name = this.name;
11099 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
11103 ['xs','sm','md','lg'].map(function(size){
11104 if (settings[size]) {
11105 cfg.cls += ' col-' + size + '-' + settings[size];
11109 var inputblock = input;
11111 if(this.hasFeedback && !this.allowBlank){
11115 cls: 'glyphicon form-control-feedback'
11119 cls : 'has-feedback',
11128 if (this.before || this.after) {
11131 cls : 'input-group',
11135 inputblock.cn.push({
11137 cls : 'input-group-addon',
11142 inputblock.cn.push(input);
11144 if(this.hasFeedback && !this.allowBlank){
11145 inputblock.cls += ' has-feedback';
11146 inputblock.cn.push(feedback);
11150 inputblock.cn.push({
11152 cls : 'input-group-addon',
11159 if (align ==='left' && this.fieldLabel.length) {
11164 cls : 'control-label',
11165 html : this.fieldLabel
11176 if(this.labelWidth > 12){
11177 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
11180 if(this.labelWidth < 13 && this.labelmd == 0){
11181 this.labelmd = this.labelWidth;
11184 if(this.labellg > 0){
11185 cfg.cn[0].cls += ' col-lg-' + this.labellg;
11186 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
11189 if(this.labelmd > 0){
11190 cfg.cn[0].cls += ' col-md-' + this.labelmd;
11191 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
11194 if(this.labelsm > 0){
11195 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
11196 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
11199 if(this.labelxs > 0){
11200 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
11201 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
11204 } else if ( this.fieldLabel.length) {
11209 //cls : 'input-group-addon',
11210 html : this.fieldLabel
11228 if (this.disabled) {
11229 input.disabled=true;
11236 * return the real textarea element.
11238 inputEl: function ()
11240 return this.el.select('textarea.form-control',true).first();
11244 * Clear any invalid styles/messages for this field
11246 clearInvalid : function()
11249 if(!this.el || this.preventMark){ // not rendered
11253 var label = this.el.select('label', true).first();
11254 var icon = this.el.select('i.fa-star', true).first();
11259 this.el.removeClass( this.validClass);
11260 this.inputEl().removeClass('is-invalid');
11262 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11264 var feedback = this.el.select('.form-control-feedback', true).first();
11267 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11272 this.fireEvent('valid', this);
11276 * Mark this field as valid
11278 markValid : function()
11280 if(!this.el || this.preventMark){ // not rendered
11284 this.el.removeClass([this.invalidClass, this.validClass]);
11285 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11287 var feedback = this.el.select('.form-control-feedback', true).first();
11290 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11293 if(this.disabled || this.allowBlank){
11297 var label = this.el.select('label', true).first();
11298 var icon = this.el.select('i.fa-star', true).first();
11303 if (Roo.bootstrap.version == 3) {
11304 this.el.addClass(this.validClass);
11306 this.inputEl().addClass('is-valid');
11310 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11312 var feedback = this.el.select('.form-control-feedback', true).first();
11315 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11316 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11321 this.fireEvent('valid', this);
11325 * Mark this field as invalid
11326 * @param {String} msg The validation message
11328 markInvalid : function(msg)
11330 if(!this.el || this.preventMark){ // not rendered
11334 this.el.removeClass([this.invalidClass, this.validClass]);
11335 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11337 var feedback = this.el.select('.form-control-feedback', true).first();
11340 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11343 if(this.disabled || this.allowBlank){
11347 var label = this.el.select('label', true).first();
11348 var icon = this.el.select('i.fa-star', true).first();
11350 if(!this.getValue().length && label && !icon){
11351 this.el.createChild({
11353 cls : 'text-danger fa fa-lg fa-star',
11354 tooltip : 'This field is required',
11355 style : 'margin-right:5px;'
11359 if (Roo.bootstrap.version == 3) {
11360 this.el.addClass(this.invalidClass);
11362 this.inputEl().addClass('is-invalid');
11365 // fixme ... this may be depricated need to test..
11366 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11368 var feedback = this.el.select('.form-control-feedback', true).first();
11371 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11373 if(this.getValue().length || this.forceFeedback){
11374 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11381 this.fireEvent('invalid', this, msg);
11389 * trigger field - base class for combo..
11394 * @class Roo.bootstrap.TriggerField
11395 * @extends Roo.bootstrap.Input
11396 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
11397 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
11398 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
11399 * for which you can provide a custom implementation. For example:
11401 var trigger = new Roo.bootstrap.TriggerField();
11402 trigger.onTriggerClick = myTriggerFn;
11403 trigger.applyTo('my-field');
11406 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
11407 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
11408 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
11409 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
11410 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
11413 * Create a new TriggerField.
11414 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
11415 * to the base TextField)
11417 Roo.bootstrap.TriggerField = function(config){
11418 this.mimicing = false;
11419 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
11422 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
11424 * @cfg {String} triggerClass A CSS class to apply to the trigger
11427 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
11432 * @cfg {Boolean} removable (true|false) special filter default false
11436 /** @cfg {Boolean} grow @hide */
11437 /** @cfg {Number} growMin @hide */
11438 /** @cfg {Number} growMax @hide */
11444 autoSize: Roo.emptyFn,
11448 deferHeight : true,
11451 actionMode : 'wrap',
11456 getAutoCreate : function(){
11458 var align = this.labelAlign || this.parentLabelAlign();
11463 cls: 'form-group' //input-group
11470 type : this.inputType,
11471 cls : 'form-control',
11472 autocomplete: 'new-password',
11473 placeholder : this.placeholder || ''
11477 input.name = this.name;
11480 input.cls += ' input-' + this.size;
11483 if (this.disabled) {
11484 input.disabled=true;
11487 var inputblock = input;
11489 if(this.hasFeedback && !this.allowBlank){
11493 cls: 'glyphicon form-control-feedback'
11496 if(this.removable && !this.editable && !this.tickable){
11498 cls : 'has-feedback',
11504 cls : 'roo-combo-removable-btn close'
11511 cls : 'has-feedback',
11520 if(this.removable && !this.editable && !this.tickable){
11522 cls : 'roo-removable',
11528 cls : 'roo-combo-removable-btn close'
11535 if (this.before || this.after) {
11538 cls : 'input-group',
11542 inputblock.cn.push({
11544 cls : 'input-group-addon input-group-prepend input-group-text',
11549 inputblock.cn.push(input);
11551 if(this.hasFeedback && !this.allowBlank){
11552 inputblock.cls += ' has-feedback';
11553 inputblock.cn.push(feedback);
11557 inputblock.cn.push({
11559 cls : 'input-group-addon input-group-append input-group-text',
11568 var ibwrap = inputblock;
11573 cls: 'roo-select2-choices',
11577 cls: 'roo-select2-search-field',
11589 cls: 'roo-select2-container input-group',
11594 cls: 'form-hidden-field'
11600 if(!this.multiple && this.showToggleBtn){
11606 if (this.caret != false) {
11609 cls: 'fa fa-' + this.caret
11616 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
11618 Roo.bootstrap.version == 3 ? caret : '',
11621 cls: 'combobox-clear',
11635 combobox.cls += ' roo-select2-container-multi';
11639 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
11640 tooltip : 'This field is required'
11642 if (Roo.bootstrap.version == 4) {
11645 style : 'display:none'
11650 if (align ==='left' && this.fieldLabel.length) {
11652 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
11659 cls : 'control-label',
11660 html : this.fieldLabel
11672 var labelCfg = cfg.cn[1];
11673 var contentCfg = cfg.cn[2];
11675 if(this.indicatorpos == 'right'){
11680 cls : 'control-label',
11684 html : this.fieldLabel
11698 labelCfg = cfg.cn[0];
11699 contentCfg = cfg.cn[1];
11702 if(this.labelWidth > 12){
11703 labelCfg.style = "width: " + this.labelWidth + 'px';
11706 if(this.labelWidth < 13 && this.labelmd == 0){
11707 this.labelmd = this.labelWidth;
11710 if(this.labellg > 0){
11711 labelCfg.cls += ' col-lg-' + this.labellg;
11712 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
11715 if(this.labelmd > 0){
11716 labelCfg.cls += ' col-md-' + this.labelmd;
11717 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
11720 if(this.labelsm > 0){
11721 labelCfg.cls += ' col-sm-' + this.labelsm;
11722 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
11725 if(this.labelxs > 0){
11726 labelCfg.cls += ' col-xs-' + this.labelxs;
11727 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
11730 } else if ( this.fieldLabel.length) {
11731 // Roo.log(" label");
11736 //cls : 'input-group-addon',
11737 html : this.fieldLabel
11745 if(this.indicatorpos == 'right'){
11753 html : this.fieldLabel
11767 // Roo.log(" no label && no align");
11774 ['xs','sm','md','lg'].map(function(size){
11775 if (settings[size]) {
11776 cfg.cls += ' col-' + size + '-' + settings[size];
11787 onResize : function(w, h){
11788 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
11789 // if(typeof w == 'number'){
11790 // var x = w - this.trigger.getWidth();
11791 // this.inputEl().setWidth(this.adjustWidth('input', x));
11792 // this.trigger.setStyle('left', x+'px');
11797 adjustSize : Roo.BoxComponent.prototype.adjustSize,
11800 getResizeEl : function(){
11801 return this.inputEl();
11805 getPositionEl : function(){
11806 return this.inputEl();
11810 alignErrorIcon : function(){
11811 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
11815 initEvents : function(){
11819 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
11820 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
11821 if(!this.multiple && this.showToggleBtn){
11822 this.trigger = this.el.select('span.dropdown-toggle',true).first();
11823 if(this.hideTrigger){
11824 this.trigger.setDisplayed(false);
11826 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
11830 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
11833 if(this.removable && !this.editable && !this.tickable){
11834 var close = this.closeTriggerEl();
11837 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
11838 close.on('click', this.removeBtnClick, this, close);
11842 //this.trigger.addClassOnOver('x-form-trigger-over');
11843 //this.trigger.addClassOnClick('x-form-trigger-click');
11846 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
11850 closeTriggerEl : function()
11852 var close = this.el.select('.roo-combo-removable-btn', true).first();
11853 return close ? close : false;
11856 removeBtnClick : function(e, h, el)
11858 e.preventDefault();
11860 if(this.fireEvent("remove", this) !== false){
11862 this.fireEvent("afterremove", this)
11866 createList : function()
11868 this.list = Roo.get(document.body).createChild({
11869 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
11870 cls: 'typeahead typeahead-long dropdown-menu',
11871 style: 'display:none'
11874 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
11879 initTrigger : function(){
11884 onDestroy : function(){
11886 this.trigger.removeAllListeners();
11887 // this.trigger.remove();
11890 // this.wrap.remove();
11892 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
11896 onFocus : function(){
11897 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
11899 if(!this.mimicing){
11900 this.wrap.addClass('x-trigger-wrap-focus');
11901 this.mimicing = true;
11902 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
11903 if(this.monitorTab){
11904 this.el.on("keydown", this.checkTab, this);
11911 checkTab : function(e){
11912 if(e.getKey() == e.TAB){
11913 this.triggerBlur();
11918 onBlur : function(){
11923 mimicBlur : function(e, t){
11925 if(!this.wrap.contains(t) && this.validateBlur()){
11926 this.triggerBlur();
11932 triggerBlur : function(){
11933 this.mimicing = false;
11934 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
11935 if(this.monitorTab){
11936 this.el.un("keydown", this.checkTab, this);
11938 //this.wrap.removeClass('x-trigger-wrap-focus');
11939 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11943 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11944 validateBlur : function(e, t){
11949 onDisable : function(){
11950 this.inputEl().dom.disabled = true;
11951 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11953 // this.wrap.addClass('x-item-disabled');
11958 onEnable : function(){
11959 this.inputEl().dom.disabled = false;
11960 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11962 // this.el.removeClass('x-item-disabled');
11967 onShow : function(){
11968 var ae = this.getActionEl();
11971 ae.dom.style.display = '';
11972 ae.dom.style.visibility = 'visible';
11978 onHide : function(){
11979 var ae = this.getActionEl();
11980 ae.dom.style.display = 'none';
11984 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11985 * by an implementing function.
11987 * @param {EventObject} e
11989 onTriggerClick : Roo.emptyFn
11993 * Ext JS Library 1.1.1
11994 * Copyright(c) 2006-2007, Ext JS, LLC.
11996 * Originally Released Under LGPL - original licence link has changed is not relivant.
11999 * <script type="text/javascript">
12004 * @class Roo.data.SortTypes
12006 * Defines the default sorting (casting?) comparison functions used when sorting data.
12008 Roo.data.SortTypes = {
12010 * Default sort that does nothing
12011 * @param {Mixed} s The value being converted
12012 * @return {Mixed} The comparison value
12014 none : function(s){
12019 * The regular expression used to strip tags
12023 stripTagsRE : /<\/?[^>]+>/gi,
12026 * Strips all HTML tags to sort on text only
12027 * @param {Mixed} s The value being converted
12028 * @return {String} The comparison value
12030 asText : function(s){
12031 return String(s).replace(this.stripTagsRE, "");
12035 * Strips all HTML tags to sort on text only - Case insensitive
12036 * @param {Mixed} s The value being converted
12037 * @return {String} The comparison value
12039 asUCText : function(s){
12040 return String(s).toUpperCase().replace(this.stripTagsRE, "");
12044 * Case insensitive string
12045 * @param {Mixed} s The value being converted
12046 * @return {String} The comparison value
12048 asUCString : function(s) {
12049 return String(s).toUpperCase();
12054 * @param {Mixed} s The value being converted
12055 * @return {Number} The comparison value
12057 asDate : function(s) {
12061 if(s instanceof Date){
12062 return s.getTime();
12064 return Date.parse(String(s));
12069 * @param {Mixed} s The value being converted
12070 * @return {Float} The comparison value
12072 asFloat : function(s) {
12073 var val = parseFloat(String(s).replace(/,/g, ""));
12082 * @param {Mixed} s The value being converted
12083 * @return {Number} The comparison value
12085 asInt : function(s) {
12086 var val = parseInt(String(s).replace(/,/g, ""));
12094 * Ext JS Library 1.1.1
12095 * Copyright(c) 2006-2007, Ext JS, LLC.
12097 * Originally Released Under LGPL - original licence link has changed is not relivant.
12100 * <script type="text/javascript">
12104 * @class Roo.data.Record
12105 * Instances of this class encapsulate both record <em>definition</em> information, and record
12106 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
12107 * to access Records cached in an {@link Roo.data.Store} object.<br>
12109 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
12110 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
12113 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
12115 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
12116 * {@link #create}. The parameters are the same.
12117 * @param {Array} data An associative Array of data values keyed by the field name.
12118 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
12119 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
12120 * not specified an integer id is generated.
12122 Roo.data.Record = function(data, id){
12123 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
12128 * Generate a constructor for a specific record layout.
12129 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
12130 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
12131 * Each field definition object may contain the following properties: <ul>
12132 * <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,
12133 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
12134 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
12135 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
12136 * is being used, then this is a string containing the javascript expression to reference the data relative to
12137 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
12138 * to the data item relative to the record element. If the mapping expression is the same as the field name,
12139 * this may be omitted.</p></li>
12140 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
12141 * <ul><li>auto (Default, implies no conversion)</li>
12146 * <li>date</li></ul></p></li>
12147 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
12148 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
12149 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
12150 * by the Reader into an object that will be stored in the Record. It is passed the
12151 * following parameters:<ul>
12152 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
12154 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
12156 * <br>usage:<br><pre><code>
12157 var TopicRecord = Roo.data.Record.create(
12158 {name: 'title', mapping: 'topic_title'},
12159 {name: 'author', mapping: 'username'},
12160 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
12161 {name: 'lastPost', mapping: 'post_time', type: 'date'},
12162 {name: 'lastPoster', mapping: 'user2'},
12163 {name: 'excerpt', mapping: 'post_text'}
12166 var myNewRecord = new TopicRecord({
12167 title: 'Do my job please',
12170 lastPost: new Date(),
12171 lastPoster: 'Animal',
12172 excerpt: 'No way dude!'
12174 myStore.add(myNewRecord);
12179 Roo.data.Record.create = function(o){
12180 var f = function(){
12181 f.superclass.constructor.apply(this, arguments);
12183 Roo.extend(f, Roo.data.Record);
12184 var p = f.prototype;
12185 p.fields = new Roo.util.MixedCollection(false, function(field){
12188 for(var i = 0, len = o.length; i < len; i++){
12189 p.fields.add(new Roo.data.Field(o[i]));
12191 f.getField = function(name){
12192 return p.fields.get(name);
12197 Roo.data.Record.AUTO_ID = 1000;
12198 Roo.data.Record.EDIT = 'edit';
12199 Roo.data.Record.REJECT = 'reject';
12200 Roo.data.Record.COMMIT = 'commit';
12202 Roo.data.Record.prototype = {
12204 * Readonly flag - true if this record has been modified.
12213 join : function(store){
12214 this.store = store;
12218 * Set the named field to the specified value.
12219 * @param {String} name The name of the field to set.
12220 * @param {Object} value The value to set the field to.
12222 set : function(name, value){
12223 if(this.data[name] == value){
12227 if(!this.modified){
12228 this.modified = {};
12230 if(typeof this.modified[name] == 'undefined'){
12231 this.modified[name] = this.data[name];
12233 this.data[name] = value;
12234 if(!this.editing && this.store){
12235 this.store.afterEdit(this);
12240 * Get the value of the named field.
12241 * @param {String} name The name of the field to get the value of.
12242 * @return {Object} The value of the field.
12244 get : function(name){
12245 return this.data[name];
12249 beginEdit : function(){
12250 this.editing = true;
12251 this.modified = {};
12255 cancelEdit : function(){
12256 this.editing = false;
12257 delete this.modified;
12261 endEdit : function(){
12262 this.editing = false;
12263 if(this.dirty && this.store){
12264 this.store.afterEdit(this);
12269 * Usually called by the {@link Roo.data.Store} which owns the Record.
12270 * Rejects all changes made to the Record since either creation, or the last commit operation.
12271 * Modified fields are reverted to their original values.
12273 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12274 * of reject operations.
12276 reject : function(){
12277 var m = this.modified;
12279 if(typeof m[n] != "function"){
12280 this.data[n] = m[n];
12283 this.dirty = false;
12284 delete this.modified;
12285 this.editing = false;
12287 this.store.afterReject(this);
12292 * Usually called by the {@link Roo.data.Store} which owns the Record.
12293 * Commits all changes made to the Record since either creation, or the last commit operation.
12295 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12296 * of commit operations.
12298 commit : function(){
12299 this.dirty = false;
12300 delete this.modified;
12301 this.editing = false;
12303 this.store.afterCommit(this);
12308 hasError : function(){
12309 return this.error != null;
12313 clearError : function(){
12318 * Creates a copy of this record.
12319 * @param {String} id (optional) A new record id if you don't want to use this record's id
12322 copy : function(newId) {
12323 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
12327 * Ext JS Library 1.1.1
12328 * Copyright(c) 2006-2007, Ext JS, LLC.
12330 * Originally Released Under LGPL - original licence link has changed is not relivant.
12333 * <script type="text/javascript">
12339 * @class Roo.data.Store
12340 * @extends Roo.util.Observable
12341 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
12342 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
12344 * 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
12345 * has no knowledge of the format of the data returned by the Proxy.<br>
12347 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
12348 * instances from the data object. These records are cached and made available through accessor functions.
12350 * Creates a new Store.
12351 * @param {Object} config A config object containing the objects needed for the Store to access data,
12352 * and read the data into Records.
12354 Roo.data.Store = function(config){
12355 this.data = new Roo.util.MixedCollection(false);
12356 this.data.getKey = function(o){
12359 this.baseParams = {};
12361 this.paramNames = {
12366 "multisort" : "_multisort"
12369 if(config && config.data){
12370 this.inlineData = config.data;
12371 delete config.data;
12374 Roo.apply(this, config);
12376 if(this.reader){ // reader passed
12377 this.reader = Roo.factory(this.reader, Roo.data);
12378 this.reader.xmodule = this.xmodule || false;
12379 if(!this.recordType){
12380 this.recordType = this.reader.recordType;
12382 if(this.reader.onMetaChange){
12383 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
12387 if(this.recordType){
12388 this.fields = this.recordType.prototype.fields;
12390 this.modified = [];
12394 * @event datachanged
12395 * Fires when the data cache has changed, and a widget which is using this Store
12396 * as a Record cache should refresh its view.
12397 * @param {Store} this
12399 datachanged : true,
12401 * @event metachange
12402 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
12403 * @param {Store} this
12404 * @param {Object} meta The JSON metadata
12409 * Fires when Records have been added to the Store
12410 * @param {Store} this
12411 * @param {Roo.data.Record[]} records The array of Records added
12412 * @param {Number} index The index at which the record(s) were added
12417 * Fires when a Record has been removed from the Store
12418 * @param {Store} this
12419 * @param {Roo.data.Record} record The Record that was removed
12420 * @param {Number} index The index at which the record was removed
12425 * Fires when a Record has been updated
12426 * @param {Store} this
12427 * @param {Roo.data.Record} record The Record that was updated
12428 * @param {String} operation The update operation being performed. Value may be one of:
12430 Roo.data.Record.EDIT
12431 Roo.data.Record.REJECT
12432 Roo.data.Record.COMMIT
12438 * Fires when the data cache has been cleared.
12439 * @param {Store} this
12443 * @event beforeload
12444 * Fires before a request is made for a new data object. If the beforeload handler returns false
12445 * the load action will be canceled.
12446 * @param {Store} this
12447 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12451 * @event beforeloadadd
12452 * Fires after a new set of Records has been loaded.
12453 * @param {Store} this
12454 * @param {Roo.data.Record[]} records The Records that were loaded
12455 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12457 beforeloadadd : true,
12460 * Fires after a new set of Records has been loaded, before they are added to the store.
12461 * @param {Store} this
12462 * @param {Roo.data.Record[]} records The Records that were loaded
12463 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12464 * @params {Object} return from reader
12468 * @event loadexception
12469 * Fires if an exception occurs in the Proxy during loading.
12470 * Called with the signature of the Proxy's "loadexception" event.
12471 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
12474 * @param {Object} return from JsonData.reader() - success, totalRecords, records
12475 * @param {Object} load options
12476 * @param {Object} jsonData from your request (normally this contains the Exception)
12478 loadexception : true
12482 this.proxy = Roo.factory(this.proxy, Roo.data);
12483 this.proxy.xmodule = this.xmodule || false;
12484 this.relayEvents(this.proxy, ["loadexception"]);
12486 this.sortToggle = {};
12487 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
12489 Roo.data.Store.superclass.constructor.call(this);
12491 if(this.inlineData){
12492 this.loadData(this.inlineData);
12493 delete this.inlineData;
12497 Roo.extend(Roo.data.Store, Roo.util.Observable, {
12499 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
12500 * without a remote query - used by combo/forms at present.
12504 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
12507 * @cfg {Array} data Inline data to be loaded when the store is initialized.
12510 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
12511 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
12514 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
12515 * on any HTTP request
12518 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
12521 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
12525 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
12526 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
12528 remoteSort : false,
12531 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
12532 * loaded or when a record is removed. (defaults to false).
12534 pruneModifiedRecords : false,
12537 lastOptions : null,
12540 * Add Records to the Store and fires the add event.
12541 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
12543 add : function(records){
12544 records = [].concat(records);
12545 for(var i = 0, len = records.length; i < len; i++){
12546 records[i].join(this);
12548 var index = this.data.length;
12549 this.data.addAll(records);
12550 this.fireEvent("add", this, records, index);
12554 * Remove a Record from the Store and fires the remove event.
12555 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
12557 remove : function(record){
12558 var index = this.data.indexOf(record);
12559 this.data.removeAt(index);
12561 if(this.pruneModifiedRecords){
12562 this.modified.remove(record);
12564 this.fireEvent("remove", this, record, index);
12568 * Remove all Records from the Store and fires the clear event.
12570 removeAll : function(){
12572 if(this.pruneModifiedRecords){
12573 this.modified = [];
12575 this.fireEvent("clear", this);
12579 * Inserts Records to the Store at the given index and fires the add event.
12580 * @param {Number} index The start index at which to insert the passed Records.
12581 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
12583 insert : function(index, records){
12584 records = [].concat(records);
12585 for(var i = 0, len = records.length; i < len; i++){
12586 this.data.insert(index, records[i]);
12587 records[i].join(this);
12589 this.fireEvent("add", this, records, index);
12593 * Get the index within the cache of the passed Record.
12594 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
12595 * @return {Number} The index of the passed Record. Returns -1 if not found.
12597 indexOf : function(record){
12598 return this.data.indexOf(record);
12602 * Get the index within the cache of the Record with the passed id.
12603 * @param {String} id The id of the Record to find.
12604 * @return {Number} The index of the Record. Returns -1 if not found.
12606 indexOfId : function(id){
12607 return this.data.indexOfKey(id);
12611 * Get the Record with the specified id.
12612 * @param {String} id The id of the Record to find.
12613 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
12615 getById : function(id){
12616 return this.data.key(id);
12620 * Get the Record at the specified index.
12621 * @param {Number} index The index of the Record to find.
12622 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
12624 getAt : function(index){
12625 return this.data.itemAt(index);
12629 * Returns a range of Records between specified indices.
12630 * @param {Number} startIndex (optional) The starting index (defaults to 0)
12631 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
12632 * @return {Roo.data.Record[]} An array of Records
12634 getRange : function(start, end){
12635 return this.data.getRange(start, end);
12639 storeOptions : function(o){
12640 o = Roo.apply({}, o);
12643 this.lastOptions = o;
12647 * Loads the Record cache from the configured Proxy using the configured Reader.
12649 * If using remote paging, then the first load call must specify the <em>start</em>
12650 * and <em>limit</em> properties in the options.params property to establish the initial
12651 * position within the dataset, and the number of Records to cache on each read from the Proxy.
12653 * <strong>It is important to note that for remote data sources, loading is asynchronous,
12654 * and this call will return before the new data has been loaded. Perform any post-processing
12655 * in a callback function, or in a "load" event handler.</strong>
12657 * @param {Object} options An object containing properties which control loading options:<ul>
12658 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
12659 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
12660 * passed the following arguments:<ul>
12661 * <li>r : Roo.data.Record[]</li>
12662 * <li>options: Options object from the load call</li>
12663 * <li>success: Boolean success indicator</li></ul></li>
12664 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
12665 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
12668 load : function(options){
12669 options = options || {};
12670 if(this.fireEvent("beforeload", this, options) !== false){
12671 this.storeOptions(options);
12672 var p = Roo.apply(options.params || {}, this.baseParams);
12673 // if meta was not loaded from remote source.. try requesting it.
12674 if (!this.reader.metaFromRemote) {
12675 p._requestMeta = 1;
12677 if(this.sortInfo && this.remoteSort){
12678 var pn = this.paramNames;
12679 p[pn["sort"]] = this.sortInfo.field;
12680 p[pn["dir"]] = this.sortInfo.direction;
12682 if (this.multiSort) {
12683 var pn = this.paramNames;
12684 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
12687 this.proxy.load(p, this.reader, this.loadRecords, this, options);
12692 * Reloads the Record cache from the configured Proxy using the configured Reader and
12693 * the options from the last load operation performed.
12694 * @param {Object} options (optional) An object containing properties which may override the options
12695 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
12696 * the most recently used options are reused).
12698 reload : function(options){
12699 this.load(Roo.applyIf(options||{}, this.lastOptions));
12703 // Called as a callback by the Reader during a load operation.
12704 loadRecords : function(o, options, success){
12705 if(!o || success === false){
12706 if(success !== false){
12707 this.fireEvent("load", this, [], options, o);
12709 if(options.callback){
12710 options.callback.call(options.scope || this, [], options, false);
12714 // if data returned failure - throw an exception.
12715 if (o.success === false) {
12716 // show a message if no listener is registered.
12717 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
12718 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
12720 // loadmask wil be hooked into this..
12721 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
12724 var r = o.records, t = o.totalRecords || r.length;
12726 this.fireEvent("beforeloadadd", this, r, options, o);
12728 if(!options || options.add !== true){
12729 if(this.pruneModifiedRecords){
12730 this.modified = [];
12732 for(var i = 0, len = r.length; i < len; i++){
12736 this.data = this.snapshot;
12737 delete this.snapshot;
12740 this.data.addAll(r);
12741 this.totalLength = t;
12743 this.fireEvent("datachanged", this);
12745 this.totalLength = Math.max(t, this.data.length+r.length);
12749 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
12751 var e = new Roo.data.Record({});
12753 e.set(this.parent.displayField, this.parent.emptyTitle);
12754 e.set(this.parent.valueField, '');
12759 this.fireEvent("load", this, r, options, o);
12760 if(options.callback){
12761 options.callback.call(options.scope || this, r, options, true);
12767 * Loads data from a passed data block. A Reader which understands the format of the data
12768 * must have been configured in the constructor.
12769 * @param {Object} data The data block from which to read the Records. The format of the data expected
12770 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
12771 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
12773 loadData : function(o, append){
12774 var r = this.reader.readRecords(o);
12775 this.loadRecords(r, {add: append}, true);
12779 * using 'cn' the nested child reader read the child array into it's child stores.
12780 * @param {Object} rec The record with a 'children array
12782 loadDataFromChildren : function(rec)
12784 this.loadData(this.reader.toLoadData(rec));
12789 * Gets the number of cached records.
12791 * <em>If using paging, this may not be the total size of the dataset. If the data object
12792 * used by the Reader contains the dataset size, then the getTotalCount() function returns
12793 * the data set size</em>
12795 getCount : function(){
12796 return this.data.length || 0;
12800 * Gets the total number of records in the dataset as returned by the server.
12802 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
12803 * the dataset size</em>
12805 getTotalCount : function(){
12806 return this.totalLength || 0;
12810 * Returns the sort state of the Store as an object with two properties:
12812 field {String} The name of the field by which the Records are sorted
12813 direction {String} The sort order, "ASC" or "DESC"
12816 getSortState : function(){
12817 return this.sortInfo;
12821 applySort : function(){
12822 if(this.sortInfo && !this.remoteSort){
12823 var s = this.sortInfo, f = s.field;
12824 var st = this.fields.get(f).sortType;
12825 var fn = function(r1, r2){
12826 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
12827 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
12829 this.data.sort(s.direction, fn);
12830 if(this.snapshot && this.snapshot != this.data){
12831 this.snapshot.sort(s.direction, fn);
12837 * Sets the default sort column and order to be used by the next load operation.
12838 * @param {String} fieldName The name of the field to sort by.
12839 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
12841 setDefaultSort : function(field, dir){
12842 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
12846 * Sort the Records.
12847 * If remote sorting is used, the sort is performed on the server, and the cache is
12848 * reloaded. If local sorting is used, the cache is sorted internally.
12849 * @param {String} fieldName The name of the field to sort by.
12850 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
12852 sort : function(fieldName, dir){
12853 var f = this.fields.get(fieldName);
12855 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
12857 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
12858 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
12863 this.sortToggle[f.name] = dir;
12864 this.sortInfo = {field: f.name, direction: dir};
12865 if(!this.remoteSort){
12867 this.fireEvent("datachanged", this);
12869 this.load(this.lastOptions);
12874 * Calls the specified function for each of the Records in the cache.
12875 * @param {Function} fn The function to call. The Record is passed as the first parameter.
12876 * Returning <em>false</em> aborts and exits the iteration.
12877 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
12879 each : function(fn, scope){
12880 this.data.each(fn, scope);
12884 * Gets all records modified since the last commit. Modified records are persisted across load operations
12885 * (e.g., during paging).
12886 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
12888 getModifiedRecords : function(){
12889 return this.modified;
12893 createFilterFn : function(property, value, anyMatch){
12894 if(!value.exec){ // not a regex
12895 value = String(value);
12896 if(value.length == 0){
12899 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
12901 return function(r){
12902 return value.test(r.data[property]);
12907 * Sums the value of <i>property</i> for each record between start and end and returns the result.
12908 * @param {String} property A field on your records
12909 * @param {Number} start The record index to start at (defaults to 0)
12910 * @param {Number} end The last record index to include (defaults to length - 1)
12911 * @return {Number} The sum
12913 sum : function(property, start, end){
12914 var rs = this.data.items, v = 0;
12915 start = start || 0;
12916 end = (end || end === 0) ? end : rs.length-1;
12918 for(var i = start; i <= end; i++){
12919 v += (rs[i].data[property] || 0);
12925 * Filter the records by a specified property.
12926 * @param {String} field A field on your records
12927 * @param {String/RegExp} value Either a string that the field
12928 * should start with or a RegExp to test against the field
12929 * @param {Boolean} anyMatch True to match any part not just the beginning
12931 filter : function(property, value, anyMatch){
12932 var fn = this.createFilterFn(property, value, anyMatch);
12933 return fn ? this.filterBy(fn) : this.clearFilter();
12937 * Filter by a function. The specified function will be called with each
12938 * record in this data source. If the function returns true the record is included,
12939 * otherwise it is filtered.
12940 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12941 * @param {Object} scope (optional) The scope of the function (defaults to this)
12943 filterBy : function(fn, scope){
12944 this.snapshot = this.snapshot || this.data;
12945 this.data = this.queryBy(fn, scope||this);
12946 this.fireEvent("datachanged", this);
12950 * Query the records by a specified property.
12951 * @param {String} field A field on your records
12952 * @param {String/RegExp} value Either a string that the field
12953 * should start with or a RegExp to test against the field
12954 * @param {Boolean} anyMatch True to match any part not just the beginning
12955 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12957 query : function(property, value, anyMatch){
12958 var fn = this.createFilterFn(property, value, anyMatch);
12959 return fn ? this.queryBy(fn) : this.data.clone();
12963 * Query by a function. The specified function will be called with each
12964 * record in this data source. If the function returns true the record is included
12966 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12967 * @param {Object} scope (optional) The scope of the function (defaults to this)
12968 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12970 queryBy : function(fn, scope){
12971 var data = this.snapshot || this.data;
12972 return data.filterBy(fn, scope||this);
12976 * Collects unique values for a particular dataIndex from this store.
12977 * @param {String} dataIndex The property to collect
12978 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12979 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12980 * @return {Array} An array of the unique values
12982 collect : function(dataIndex, allowNull, bypassFilter){
12983 var d = (bypassFilter === true && this.snapshot) ?
12984 this.snapshot.items : this.data.items;
12985 var v, sv, r = [], l = {};
12986 for(var i = 0, len = d.length; i < len; i++){
12987 v = d[i].data[dataIndex];
12989 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12998 * Revert to a view of the Record cache with no filtering applied.
12999 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
13001 clearFilter : function(suppressEvent){
13002 if(this.snapshot && this.snapshot != this.data){
13003 this.data = this.snapshot;
13004 delete this.snapshot;
13005 if(suppressEvent !== true){
13006 this.fireEvent("datachanged", this);
13012 afterEdit : function(record){
13013 if(this.modified.indexOf(record) == -1){
13014 this.modified.push(record);
13016 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
13020 afterReject : function(record){
13021 this.modified.remove(record);
13022 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
13026 afterCommit : function(record){
13027 this.modified.remove(record);
13028 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
13032 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
13033 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
13035 commitChanges : function(){
13036 var m = this.modified.slice(0);
13037 this.modified = [];
13038 for(var i = 0, len = m.length; i < len; i++){
13044 * Cancel outstanding changes on all changed records.
13046 rejectChanges : function(){
13047 var m = this.modified.slice(0);
13048 this.modified = [];
13049 for(var i = 0, len = m.length; i < len; i++){
13054 onMetaChange : function(meta, rtype, o){
13055 this.recordType = rtype;
13056 this.fields = rtype.prototype.fields;
13057 delete this.snapshot;
13058 this.sortInfo = meta.sortInfo || this.sortInfo;
13059 this.modified = [];
13060 this.fireEvent('metachange', this, this.reader.meta);
13063 moveIndex : function(data, type)
13065 var index = this.indexOf(data);
13067 var newIndex = index + type;
13071 this.insert(newIndex, data);
13076 * Ext JS Library 1.1.1
13077 * Copyright(c) 2006-2007, Ext JS, LLC.
13079 * Originally Released Under LGPL - original licence link has changed is not relivant.
13082 * <script type="text/javascript">
13086 * @class Roo.data.SimpleStore
13087 * @extends Roo.data.Store
13088 * Small helper class to make creating Stores from Array data easier.
13089 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
13090 * @cfg {Array} fields An array of field definition objects, or field name strings.
13091 * @cfg {Object} an existing reader (eg. copied from another store)
13092 * @cfg {Array} data The multi-dimensional array of data
13094 * @param {Object} config
13096 Roo.data.SimpleStore = function(config)
13098 Roo.data.SimpleStore.superclass.constructor.call(this, {
13100 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
13103 Roo.data.Record.create(config.fields)
13105 proxy : new Roo.data.MemoryProxy(config.data)
13109 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
13111 * Ext JS Library 1.1.1
13112 * Copyright(c) 2006-2007, Ext JS, LLC.
13114 * Originally Released Under LGPL - original licence link has changed is not relivant.
13117 * <script type="text/javascript">
13122 * @extends Roo.data.Store
13123 * @class Roo.data.JsonStore
13124 * Small helper class to make creating Stores for JSON data easier. <br/>
13126 var store = new Roo.data.JsonStore({
13127 url: 'get-images.php',
13129 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
13132 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
13133 * JsonReader and HttpProxy (unless inline data is provided).</b>
13134 * @cfg {Array} fields An array of field definition objects, or field name strings.
13136 * @param {Object} config
13138 Roo.data.JsonStore = function(c){
13139 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
13140 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
13141 reader: new Roo.data.JsonReader(c, c.fields)
13144 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
13146 * Ext JS Library 1.1.1
13147 * Copyright(c) 2006-2007, Ext JS, LLC.
13149 * Originally Released Under LGPL - original licence link has changed is not relivant.
13152 * <script type="text/javascript">
13156 Roo.data.Field = function(config){
13157 if(typeof config == "string"){
13158 config = {name: config};
13160 Roo.apply(this, config);
13163 this.type = "auto";
13166 var st = Roo.data.SortTypes;
13167 // named sortTypes are supported, here we look them up
13168 if(typeof this.sortType == "string"){
13169 this.sortType = st[this.sortType];
13172 // set default sortType for strings and dates
13173 if(!this.sortType){
13176 this.sortType = st.asUCString;
13179 this.sortType = st.asDate;
13182 this.sortType = st.none;
13187 var stripRe = /[\$,%]/g;
13189 // prebuilt conversion function for this field, instead of
13190 // switching every time we're reading a value
13192 var cv, dateFormat = this.dateFormat;
13197 cv = function(v){ return v; };
13200 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
13204 return v !== undefined && v !== null && v !== '' ?
13205 parseInt(String(v).replace(stripRe, ""), 10) : '';
13210 return v !== undefined && v !== null && v !== '' ?
13211 parseFloat(String(v).replace(stripRe, ""), 10) : '';
13216 cv = function(v){ return v === true || v === "true" || v == 1; };
13223 if(v instanceof Date){
13227 if(dateFormat == "timestamp"){
13228 return new Date(v*1000);
13230 return Date.parseDate(v, dateFormat);
13232 var parsed = Date.parse(v);
13233 return parsed ? new Date(parsed) : null;
13242 Roo.data.Field.prototype = {
13250 * Ext JS Library 1.1.1
13251 * Copyright(c) 2006-2007, Ext JS, LLC.
13253 * Originally Released Under LGPL - original licence link has changed is not relivant.
13256 * <script type="text/javascript">
13259 // Base class for reading structured data from a data source. This class is intended to be
13260 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
13263 * @class Roo.data.DataReader
13264 * Base class for reading structured data from a data source. This class is intended to be
13265 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
13268 Roo.data.DataReader = function(meta, recordType){
13272 this.recordType = recordType instanceof Array ?
13273 Roo.data.Record.create(recordType) : recordType;
13276 Roo.data.DataReader.prototype = {
13279 readerType : 'Data',
13281 * Create an empty record
13282 * @param {Object} data (optional) - overlay some values
13283 * @return {Roo.data.Record} record created.
13285 newRow : function(d) {
13287 this.recordType.prototype.fields.each(function(c) {
13289 case 'int' : da[c.name] = 0; break;
13290 case 'date' : da[c.name] = new Date(); break;
13291 case 'float' : da[c.name] = 0.0; break;
13292 case 'boolean' : da[c.name] = false; break;
13293 default : da[c.name] = ""; break;
13297 return new this.recordType(Roo.apply(da, d));
13303 * Ext JS Library 1.1.1
13304 * Copyright(c) 2006-2007, Ext JS, LLC.
13306 * Originally Released Under LGPL - original licence link has changed is not relivant.
13309 * <script type="text/javascript">
13313 * @class Roo.data.DataProxy
13314 * @extends Roo.data.Observable
13315 * This class is an abstract base class for implementations which provide retrieval of
13316 * unformatted data objects.<br>
13318 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
13319 * (of the appropriate type which knows how to parse the data object) to provide a block of
13320 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
13322 * Custom implementations must implement the load method as described in
13323 * {@link Roo.data.HttpProxy#load}.
13325 Roo.data.DataProxy = function(){
13328 * @event beforeload
13329 * Fires before a network request is made to retrieve a data object.
13330 * @param {Object} This DataProxy object.
13331 * @param {Object} params The params parameter to the load function.
13336 * Fires before the load method's callback is called.
13337 * @param {Object} This DataProxy object.
13338 * @param {Object} o The data object.
13339 * @param {Object} arg The callback argument object passed to the load function.
13343 * @event loadexception
13344 * Fires if an Exception occurs during data retrieval.
13345 * @param {Object} This DataProxy object.
13346 * @param {Object} o The data object.
13347 * @param {Object} arg The callback argument object passed to the load function.
13348 * @param {Object} e The Exception.
13350 loadexception : true
13352 Roo.data.DataProxy.superclass.constructor.call(this);
13355 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
13358 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
13362 * Ext JS Library 1.1.1
13363 * Copyright(c) 2006-2007, Ext JS, LLC.
13365 * Originally Released Under LGPL - original licence link has changed is not relivant.
13368 * <script type="text/javascript">
13371 * @class Roo.data.MemoryProxy
13372 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
13373 * to the Reader when its load method is called.
13375 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
13377 Roo.data.MemoryProxy = function(data){
13381 Roo.data.MemoryProxy.superclass.constructor.call(this);
13385 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
13388 * Load data from the requested source (in this case an in-memory
13389 * data object passed to the constructor), read the data object into
13390 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
13391 * process that block using the passed callback.
13392 * @param {Object} params This parameter is not used by the MemoryProxy class.
13393 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13394 * object into a block of Roo.data.Records.
13395 * @param {Function} callback The function into which to pass the block of Roo.data.records.
13396 * The function must be passed <ul>
13397 * <li>The Record block object</li>
13398 * <li>The "arg" argument from the load function</li>
13399 * <li>A boolean success indicator</li>
13401 * @param {Object} scope The scope in which to call the callback
13402 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13404 load : function(params, reader, callback, scope, arg){
13405 params = params || {};
13408 result = reader.readRecords(params.data ? params.data :this.data);
13410 this.fireEvent("loadexception", this, arg, null, e);
13411 callback.call(scope, null, arg, false);
13414 callback.call(scope, result, arg, true);
13418 update : function(params, records){
13423 * Ext JS Library 1.1.1
13424 * Copyright(c) 2006-2007, Ext JS, LLC.
13426 * Originally Released Under LGPL - original licence link has changed is not relivant.
13429 * <script type="text/javascript">
13432 * @class Roo.data.HttpProxy
13433 * @extends Roo.data.DataProxy
13434 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
13435 * configured to reference a certain URL.<br><br>
13437 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
13438 * from which the running page was served.<br><br>
13440 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
13442 * Be aware that to enable the browser to parse an XML document, the server must set
13443 * the Content-Type header in the HTTP response to "text/xml".
13445 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
13446 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
13447 * will be used to make the request.
13449 Roo.data.HttpProxy = function(conn){
13450 Roo.data.HttpProxy.superclass.constructor.call(this);
13451 // is conn a conn config or a real conn?
13453 this.useAjax = !conn || !conn.events;
13457 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
13458 // thse are take from connection...
13461 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
13464 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
13465 * extra parameters to each request made by this object. (defaults to undefined)
13468 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
13469 * to each request made by this object. (defaults to undefined)
13472 * @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)
13475 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13478 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
13484 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13488 * Return the {@link Roo.data.Connection} object being used by this Proxy.
13489 * @return {Connection} The Connection object. This object may be used to subscribe to events on
13490 * a finer-grained basis than the DataProxy events.
13492 getConnection : function(){
13493 return this.useAjax ? Roo.Ajax : this.conn;
13497 * Load data from the configured {@link Roo.data.Connection}, read the data object into
13498 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
13499 * process that block using the passed callback.
13500 * @param {Object} params An object containing properties which are to be used as HTTP parameters
13501 * for the request to the remote server.
13502 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13503 * object into a block of Roo.data.Records.
13504 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
13505 * The function must be passed <ul>
13506 * <li>The Record block object</li>
13507 * <li>The "arg" argument from the load function</li>
13508 * <li>A boolean success indicator</li>
13510 * @param {Object} scope The scope in which to call the callback
13511 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13513 load : function(params, reader, callback, scope, arg){
13514 if(this.fireEvent("beforeload", this, params) !== false){
13516 params : params || {},
13518 callback : callback,
13523 callback : this.loadResponse,
13527 Roo.applyIf(o, this.conn);
13528 if(this.activeRequest){
13529 Roo.Ajax.abort(this.activeRequest);
13531 this.activeRequest = Roo.Ajax.request(o);
13533 this.conn.request(o);
13536 callback.call(scope||this, null, arg, false);
13541 loadResponse : function(o, success, response){
13542 delete this.activeRequest;
13544 this.fireEvent("loadexception", this, o, response);
13545 o.request.callback.call(o.request.scope, null, o.request.arg, false);
13550 result = o.reader.read(response);
13552 this.fireEvent("loadexception", this, o, response, e);
13553 o.request.callback.call(o.request.scope, null, o.request.arg, false);
13557 this.fireEvent("load", this, o, o.request.arg);
13558 o.request.callback.call(o.request.scope, result, o.request.arg, true);
13562 update : function(dataSet){
13567 updateResponse : function(dataSet){
13572 * Ext JS Library 1.1.1
13573 * Copyright(c) 2006-2007, Ext JS, LLC.
13575 * Originally Released Under LGPL - original licence link has changed is not relivant.
13578 * <script type="text/javascript">
13582 * @class Roo.data.ScriptTagProxy
13583 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
13584 * other than the originating domain of the running page.<br><br>
13586 * <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
13587 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
13589 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
13590 * source code that is used as the source inside a <script> tag.<br><br>
13592 * In order for the browser to process the returned data, the server must wrap the data object
13593 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
13594 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
13595 * depending on whether the callback name was passed:
13598 boolean scriptTag = false;
13599 String cb = request.getParameter("callback");
13602 response.setContentType("text/javascript");
13604 response.setContentType("application/x-json");
13606 Writer out = response.getWriter();
13608 out.write(cb + "(");
13610 out.print(dataBlock.toJsonString());
13617 * @param {Object} config A configuration object.
13619 Roo.data.ScriptTagProxy = function(config){
13620 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
13621 Roo.apply(this, config);
13622 this.head = document.getElementsByTagName("head")[0];
13625 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
13627 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
13629 * @cfg {String} url The URL from which to request the data object.
13632 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
13636 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
13637 * the server the name of the callback function set up by the load call to process the returned data object.
13638 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
13639 * javascript output which calls this named function passing the data object as its only parameter.
13641 callbackParam : "callback",
13643 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
13644 * name to the request.
13649 * Load data from the configured URL, read the data object into
13650 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
13651 * process that block using the passed callback.
13652 * @param {Object} params An object containing properties which are to be used as HTTP parameters
13653 * for the request to the remote server.
13654 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13655 * object into a block of Roo.data.Records.
13656 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
13657 * The function must be passed <ul>
13658 * <li>The Record block object</li>
13659 * <li>The "arg" argument from the load function</li>
13660 * <li>A boolean success indicator</li>
13662 * @param {Object} scope The scope in which to call the callback
13663 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13665 load : function(params, reader, callback, scope, arg){
13666 if(this.fireEvent("beforeload", this, params) !== false){
13668 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
13670 var url = this.url;
13671 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
13673 url += "&_dc=" + (new Date().getTime());
13675 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
13678 cb : "stcCallback"+transId,
13679 scriptId : "stcScript"+transId,
13683 callback : callback,
13689 window[trans.cb] = function(o){
13690 conn.handleResponse(o, trans);
13693 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
13695 if(this.autoAbort !== false){
13699 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
13701 var script = document.createElement("script");
13702 script.setAttribute("src", url);
13703 script.setAttribute("type", "text/javascript");
13704 script.setAttribute("id", trans.scriptId);
13705 this.head.appendChild(script);
13707 this.trans = trans;
13709 callback.call(scope||this, null, arg, false);
13714 isLoading : function(){
13715 return this.trans ? true : false;
13719 * Abort the current server request.
13721 abort : function(){
13722 if(this.isLoading()){
13723 this.destroyTrans(this.trans);
13728 destroyTrans : function(trans, isLoaded){
13729 this.head.removeChild(document.getElementById(trans.scriptId));
13730 clearTimeout(trans.timeoutId);
13732 window[trans.cb] = undefined;
13734 delete window[trans.cb];
13737 // if hasn't been loaded, wait for load to remove it to prevent script error
13738 window[trans.cb] = function(){
13739 window[trans.cb] = undefined;
13741 delete window[trans.cb];
13748 handleResponse : function(o, trans){
13749 this.trans = false;
13750 this.destroyTrans(trans, true);
13753 result = trans.reader.readRecords(o);
13755 this.fireEvent("loadexception", this, o, trans.arg, e);
13756 trans.callback.call(trans.scope||window, null, trans.arg, false);
13759 this.fireEvent("load", this, o, trans.arg);
13760 trans.callback.call(trans.scope||window, result, trans.arg, true);
13764 handleFailure : function(trans){
13765 this.trans = false;
13766 this.destroyTrans(trans, false);
13767 this.fireEvent("loadexception", this, null, trans.arg);
13768 trans.callback.call(trans.scope||window, null, trans.arg, false);
13772 * Ext JS Library 1.1.1
13773 * Copyright(c) 2006-2007, Ext JS, LLC.
13775 * Originally Released Under LGPL - original licence link has changed is not relivant.
13778 * <script type="text/javascript">
13782 * @class Roo.data.JsonReader
13783 * @extends Roo.data.DataReader
13784 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
13785 * based on mappings in a provided Roo.data.Record constructor.
13787 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
13788 * in the reply previously.
13793 var RecordDef = Roo.data.Record.create([
13794 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
13795 {name: 'occupation'} // This field will use "occupation" as the mapping.
13797 var myReader = new Roo.data.JsonReader({
13798 totalProperty: "results", // The property which contains the total dataset size (optional)
13799 root: "rows", // The property which contains an Array of row objects
13800 id: "id" // The property within each row object that provides an ID for the record (optional)
13804 * This would consume a JSON file like this:
13806 { 'results': 2, 'rows': [
13807 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
13808 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
13811 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
13812 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
13813 * paged from the remote server.
13814 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
13815 * @cfg {String} root name of the property which contains the Array of row objects.
13816 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13817 * @cfg {Array} fields Array of field definition objects
13819 * Create a new JsonReader
13820 * @param {Object} meta Metadata configuration options
13821 * @param {Object} recordType Either an Array of field definition objects,
13822 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
13824 Roo.data.JsonReader = function(meta, recordType){
13827 // set some defaults:
13828 Roo.applyIf(meta, {
13829 totalProperty: 'total',
13830 successProperty : 'success',
13835 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13837 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
13839 readerType : 'Json',
13842 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
13843 * Used by Store query builder to append _requestMeta to params.
13846 metaFromRemote : false,
13848 * This method is only used by a DataProxy which has retrieved data from a remote server.
13849 * @param {Object} response The XHR object which contains the JSON data in its responseText.
13850 * @return {Object} data A data block which is used by an Roo.data.Store object as
13851 * a cache of Roo.data.Records.
13853 read : function(response){
13854 var json = response.responseText;
13856 var o = /* eval:var:o */ eval("("+json+")");
13858 throw {message: "JsonReader.read: Json object not found"};
13864 this.metaFromRemote = true;
13865 this.meta = o.metaData;
13866 this.recordType = Roo.data.Record.create(o.metaData.fields);
13867 this.onMetaChange(this.meta, this.recordType, o);
13869 return this.readRecords(o);
13872 // private function a store will implement
13873 onMetaChange : function(meta, recordType, o){
13880 simpleAccess: function(obj, subsc) {
13887 getJsonAccessor: function(){
13889 return function(expr) {
13891 return(re.test(expr))
13892 ? new Function("obj", "return obj." + expr)
13897 return Roo.emptyFn;
13902 * Create a data block containing Roo.data.Records from an XML document.
13903 * @param {Object} o An object which contains an Array of row objects in the property specified
13904 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
13905 * which contains the total size of the dataset.
13906 * @return {Object} data A data block which is used by an Roo.data.Store object as
13907 * a cache of Roo.data.Records.
13909 readRecords : function(o){
13911 * After any data loads, the raw JSON data is available for further custom processing.
13915 var s = this.meta, Record = this.recordType,
13916 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
13918 // Generate extraction functions for the totalProperty, the root, the id, and for each field
13920 if(s.totalProperty) {
13921 this.getTotal = this.getJsonAccessor(s.totalProperty);
13923 if(s.successProperty) {
13924 this.getSuccess = this.getJsonAccessor(s.successProperty);
13926 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
13928 var g = this.getJsonAccessor(s.id);
13929 this.getId = function(rec) {
13931 return (r === undefined || r === "") ? null : r;
13934 this.getId = function(){return null;};
13937 for(var jj = 0; jj < fl; jj++){
13939 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
13940 this.ef[jj] = this.getJsonAccessor(map);
13944 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
13945 if(s.totalProperty){
13946 var vt = parseInt(this.getTotal(o), 10);
13951 if(s.successProperty){
13952 var vs = this.getSuccess(o);
13953 if(vs === false || vs === 'false'){
13958 for(var i = 0; i < c; i++){
13961 var id = this.getId(n);
13962 for(var j = 0; j < fl; j++){
13964 var v = this.ef[j](n);
13966 Roo.log('missing convert for ' + f.name);
13970 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13972 var record = new Record(values, id);
13974 records[i] = record;
13980 totalRecords : totalRecords
13983 // used when loading children.. @see loadDataFromChildren
13984 toLoadData: function(rec)
13986 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
13987 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
13988 return { data : data, total : data.length };
13993 * Ext JS Library 1.1.1
13994 * Copyright(c) 2006-2007, Ext JS, LLC.
13996 * Originally Released Under LGPL - original licence link has changed is not relivant.
13999 * <script type="text/javascript">
14003 * @class Roo.data.ArrayReader
14004 * @extends Roo.data.DataReader
14005 * Data reader class to create an Array of Roo.data.Record objects from an Array.
14006 * Each element of that Array represents a row of data fields. The
14007 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
14008 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
14012 var RecordDef = Roo.data.Record.create([
14013 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
14014 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
14016 var myReader = new Roo.data.ArrayReader({
14017 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
14021 * This would consume an Array like this:
14023 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
14027 * Create a new JsonReader
14028 * @param {Object} meta Metadata configuration options.
14029 * @param {Object|Array} recordType Either an Array of field definition objects
14031 * @cfg {Array} fields Array of field definition objects
14032 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14033 * as specified to {@link Roo.data.Record#create},
14034 * or an {@link Roo.data.Record} object
14037 * created using {@link Roo.data.Record#create}.
14039 Roo.data.ArrayReader = function(meta, recordType)
14041 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14044 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
14047 * Create a data block containing Roo.data.Records from an XML document.
14048 * @param {Object} o An Array of row objects which represents the dataset.
14049 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
14050 * a cache of Roo.data.Records.
14052 readRecords : function(o)
14054 var sid = this.meta ? this.meta.id : null;
14055 var recordType = this.recordType, fields = recordType.prototype.fields;
14058 for(var i = 0; i < root.length; i++){
14061 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
14062 for(var j = 0, jlen = fields.length; j < jlen; j++){
14063 var f = fields.items[j];
14064 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
14065 var v = n[k] !== undefined ? n[k] : f.defaultValue;
14067 values[f.name] = v;
14069 var record = new recordType(values, id);
14071 records[records.length] = record;
14075 totalRecords : records.length
14078 // used when loading children.. @see loadDataFromChildren
14079 toLoadData: function(rec)
14081 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14082 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14093 * @class Roo.bootstrap.ComboBox
14094 * @extends Roo.bootstrap.TriggerField
14095 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
14096 * @cfg {Boolean} append (true|false) default false
14097 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
14098 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
14099 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
14100 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
14101 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
14102 * @cfg {Boolean} animate default true
14103 * @cfg {Boolean} emptyResultText only for touch device
14104 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
14105 * @cfg {String} emptyTitle default ''
14107 * Create a new ComboBox.
14108 * @param {Object} config Configuration options
14110 Roo.bootstrap.ComboBox = function(config){
14111 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
14115 * Fires when the dropdown list is expanded
14116 * @param {Roo.bootstrap.ComboBox} combo This combo box
14121 * Fires when the dropdown list is collapsed
14122 * @param {Roo.bootstrap.ComboBox} combo This combo box
14126 * @event beforeselect
14127 * Fires before a list item is selected. Return false to cancel the selection.
14128 * @param {Roo.bootstrap.ComboBox} combo This combo box
14129 * @param {Roo.data.Record} record The data record returned from the underlying store
14130 * @param {Number} index The index of the selected item in the dropdown list
14132 'beforeselect' : true,
14135 * Fires when a list item is selected
14136 * @param {Roo.bootstrap.ComboBox} combo This combo box
14137 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
14138 * @param {Number} index The index of the selected item in the dropdown list
14142 * @event beforequery
14143 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
14144 * The event object passed has these properties:
14145 * @param {Roo.bootstrap.ComboBox} combo This combo box
14146 * @param {String} query The query
14147 * @param {Boolean} forceAll true to force "all" query
14148 * @param {Boolean} cancel true to cancel the query
14149 * @param {Object} e The query event object
14151 'beforequery': true,
14154 * Fires when the 'add' icon is pressed (add a listener to enable add button)
14155 * @param {Roo.bootstrap.ComboBox} combo This combo box
14160 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
14161 * @param {Roo.bootstrap.ComboBox} combo This combo box
14162 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
14167 * Fires when the remove value from the combobox array
14168 * @param {Roo.bootstrap.ComboBox} combo This combo box
14172 * @event afterremove
14173 * Fires when the remove value from the combobox array
14174 * @param {Roo.bootstrap.ComboBox} combo This combo box
14176 'afterremove' : true,
14178 * @event specialfilter
14179 * Fires when specialfilter
14180 * @param {Roo.bootstrap.ComboBox} combo This combo box
14182 'specialfilter' : true,
14185 * Fires when tick the element
14186 * @param {Roo.bootstrap.ComboBox} combo This combo box
14190 * @event touchviewdisplay
14191 * Fires when touch view require special display (default is using displayField)
14192 * @param {Roo.bootstrap.ComboBox} combo This combo box
14193 * @param {Object} cfg set html .
14195 'touchviewdisplay' : true
14200 this.tickItems = [];
14202 this.selectedIndex = -1;
14203 if(this.mode == 'local'){
14204 if(config.queryDelay === undefined){
14205 this.queryDelay = 10;
14207 if(config.minChars === undefined){
14213 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
14216 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
14217 * rendering into an Roo.Editor, defaults to false)
14220 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
14221 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
14224 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
14227 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
14228 * the dropdown list (defaults to undefined, with no header element)
14232 * @cfg {String/Roo.Template} tpl The template to use to render the output
14236 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
14238 listWidth: undefined,
14240 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
14241 * mode = 'remote' or 'text' if mode = 'local')
14243 displayField: undefined,
14246 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
14247 * mode = 'remote' or 'value' if mode = 'local').
14248 * Note: use of a valueField requires the user make a selection
14249 * in order for a value to be mapped.
14251 valueField: undefined,
14253 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
14258 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
14259 * field's data value (defaults to the underlying DOM element's name)
14261 hiddenName: undefined,
14263 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
14267 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
14269 selectedClass: 'active',
14272 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14276 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
14277 * anchor positions (defaults to 'tl-bl')
14279 listAlign: 'tl-bl?',
14281 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
14285 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
14286 * query specified by the allQuery config option (defaults to 'query')
14288 triggerAction: 'query',
14290 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
14291 * (defaults to 4, does not apply if editable = false)
14295 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
14296 * delay (typeAheadDelay) if it matches a known value (defaults to false)
14300 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
14301 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
14305 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
14306 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
14310 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
14311 * when editable = true (defaults to false)
14313 selectOnFocus:false,
14315 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
14317 queryParam: 'query',
14319 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
14320 * when mode = 'remote' (defaults to 'Loading...')
14322 loadingText: 'Loading...',
14324 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
14328 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
14332 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
14333 * traditional select (defaults to true)
14337 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
14341 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
14345 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
14346 * listWidth has a higher value)
14350 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
14351 * allow the user to set arbitrary text into the field (defaults to false)
14353 forceSelection:false,
14355 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
14356 * if typeAhead = true (defaults to 250)
14358 typeAheadDelay : 250,
14360 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
14361 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
14363 valueNotFoundText : undefined,
14365 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
14367 blockFocus : false,
14370 * @cfg {Boolean} disableClear Disable showing of clear button.
14372 disableClear : false,
14374 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
14376 alwaysQuery : false,
14379 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
14384 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
14386 invalidClass : "has-warning",
14389 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
14391 validClass : "has-success",
14394 * @cfg {Boolean} specialFilter (true|false) special filter default false
14396 specialFilter : false,
14399 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
14401 mobileTouchView : true,
14404 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
14406 useNativeIOS : false,
14409 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
14411 mobile_restrict_height : false,
14413 ios_options : false,
14425 btnPosition : 'right',
14426 triggerList : true,
14427 showToggleBtn : true,
14429 emptyResultText: 'Empty',
14430 triggerText : 'Select',
14433 // element that contains real text value.. (when hidden is used..)
14435 getAutoCreate : function()
14440 * Render classic select for iso
14443 if(Roo.isIOS && this.useNativeIOS){
14444 cfg = this.getAutoCreateNativeIOS();
14452 if(Roo.isTouch && this.mobileTouchView){
14453 cfg = this.getAutoCreateTouchView();
14460 if(!this.tickable){
14461 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
14466 * ComboBox with tickable selections
14469 var align = this.labelAlign || this.parentLabelAlign();
14472 cls : 'form-group roo-combobox-tickable' //input-group
14475 var btn_text_select = '';
14476 var btn_text_done = '';
14477 var btn_text_cancel = '';
14479 if (this.btn_text_show) {
14480 btn_text_select = 'Select';
14481 btn_text_done = 'Done';
14482 btn_text_cancel = 'Cancel';
14487 cls : 'tickable-buttons',
14492 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
14493 //html : this.triggerText
14494 html: btn_text_select
14500 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
14502 html: btn_text_done
14508 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
14510 html: btn_text_cancel
14516 buttons.cn.unshift({
14518 cls: 'roo-select2-search-field-input'
14524 Roo.each(buttons.cn, function(c){
14526 c.cls += ' btn-' + _this.size;
14529 if (_this.disabled) {
14536 style : 'display: contents',
14541 cls: 'form-hidden-field'
14545 cls: 'roo-select2-choices',
14549 cls: 'roo-select2-search-field',
14560 cls: 'roo-select2-container input-group roo-select2-container-multi',
14566 // cls: 'typeahead typeahead-long dropdown-menu',
14567 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
14572 if(this.hasFeedback && !this.allowBlank){
14576 cls: 'glyphicon form-control-feedback'
14579 combobox.cn.push(feedback);
14584 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
14585 tooltip : 'This field is required'
14587 if (Roo.bootstrap.version == 4) {
14590 style : 'display:none'
14593 if (align ==='left' && this.fieldLabel.length) {
14595 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
14602 cls : 'control-label col-form-label',
14603 html : this.fieldLabel
14615 var labelCfg = cfg.cn[1];
14616 var contentCfg = cfg.cn[2];
14619 if(this.indicatorpos == 'right'){
14625 cls : 'control-label col-form-label',
14629 html : this.fieldLabel
14645 labelCfg = cfg.cn[0];
14646 contentCfg = cfg.cn[1];
14650 if(this.labelWidth > 12){
14651 labelCfg.style = "width: " + this.labelWidth + 'px';
14654 if(this.labelWidth < 13 && this.labelmd == 0){
14655 this.labelmd = this.labelWidth;
14658 if(this.labellg > 0){
14659 labelCfg.cls += ' col-lg-' + this.labellg;
14660 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14663 if(this.labelmd > 0){
14664 labelCfg.cls += ' col-md-' + this.labelmd;
14665 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14668 if(this.labelsm > 0){
14669 labelCfg.cls += ' col-sm-' + this.labelsm;
14670 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14673 if(this.labelxs > 0){
14674 labelCfg.cls += ' col-xs-' + this.labelxs;
14675 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14679 } else if ( this.fieldLabel.length) {
14680 // Roo.log(" label");
14685 //cls : 'input-group-addon',
14686 html : this.fieldLabel
14691 if(this.indicatorpos == 'right'){
14695 //cls : 'input-group-addon',
14696 html : this.fieldLabel
14706 // Roo.log(" no label && no align");
14713 ['xs','sm','md','lg'].map(function(size){
14714 if (settings[size]) {
14715 cfg.cls += ' col-' + size + '-' + settings[size];
14723 _initEventsCalled : false,
14726 initEvents: function()
14728 if (this._initEventsCalled) { // as we call render... prevent looping...
14731 this._initEventsCalled = true;
14734 throw "can not find store for combo";
14737 this.indicator = this.indicatorEl();
14739 this.store = Roo.factory(this.store, Roo.data);
14740 this.store.parent = this;
14742 // if we are building from html. then this element is so complex, that we can not really
14743 // use the rendered HTML.
14744 // so we have to trash and replace the previous code.
14745 if (Roo.XComponent.build_from_html) {
14746 // remove this element....
14747 var e = this.el.dom, k=0;
14748 while (e ) { e = e.previousSibling; ++k;}
14753 this.rendered = false;
14755 this.render(this.parent().getChildContainer(true), k);
14758 if(Roo.isIOS && this.useNativeIOS){
14759 this.initIOSView();
14767 if(Roo.isTouch && this.mobileTouchView){
14768 this.initTouchView();
14773 this.initTickableEvents();
14777 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
14779 if(this.hiddenName){
14781 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14783 this.hiddenField.dom.value =
14784 this.hiddenValue !== undefined ? this.hiddenValue :
14785 this.value !== undefined ? this.value : '';
14787 // prevent input submission
14788 this.el.dom.removeAttribute('name');
14789 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14794 // this.el.dom.setAttribute('autocomplete', 'off');
14797 var cls = 'x-combo-list';
14799 //this.list = new Roo.Layer({
14800 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
14806 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14807 _this.list.setWidth(lw);
14810 this.list.on('mouseover', this.onViewOver, this);
14811 this.list.on('mousemove', this.onViewMove, this);
14812 this.list.on('scroll', this.onViewScroll, this);
14815 this.list.swallowEvent('mousewheel');
14816 this.assetHeight = 0;
14819 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
14820 this.assetHeight += this.header.getHeight();
14823 this.innerList = this.list.createChild({cls:cls+'-inner'});
14824 this.innerList.on('mouseover', this.onViewOver, this);
14825 this.innerList.on('mousemove', this.onViewMove, this);
14826 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14828 if(this.allowBlank && !this.pageSize && !this.disableClear){
14829 this.footer = this.list.createChild({cls:cls+'-ft'});
14830 this.pageTb = new Roo.Toolbar(this.footer);
14834 this.footer = this.list.createChild({cls:cls+'-ft'});
14835 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
14836 {pageSize: this.pageSize});
14840 if (this.pageTb && this.allowBlank && !this.disableClear) {
14842 this.pageTb.add(new Roo.Toolbar.Fill(), {
14843 cls: 'x-btn-icon x-btn-clear',
14845 handler: function()
14848 _this.clearValue();
14849 _this.onSelect(false, -1);
14854 this.assetHeight += this.footer.getHeight();
14859 this.tpl = Roo.bootstrap.version == 4 ?
14860 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
14861 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
14864 this.view = new Roo.View(this.list, this.tpl, {
14865 singleSelect:true, store: this.store, selectedClass: this.selectedClass
14867 //this.view.wrapEl.setDisplayed(false);
14868 this.view.on('click', this.onViewClick, this);
14871 this.store.on('beforeload', this.onBeforeLoad, this);
14872 this.store.on('load', this.onLoad, this);
14873 this.store.on('loadexception', this.onLoadException, this);
14875 if(this.resizable){
14876 this.resizer = new Roo.Resizable(this.list, {
14877 pinned:true, handles:'se'
14879 this.resizer.on('resize', function(r, w, h){
14880 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
14881 this.listWidth = w;
14882 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
14883 this.restrictHeight();
14885 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
14888 if(!this.editable){
14889 this.editable = true;
14890 this.setEditable(false);
14895 if (typeof(this.events.add.listeners) != 'undefined') {
14897 this.addicon = this.wrap.createChild(
14898 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
14900 this.addicon.on('click', function(e) {
14901 this.fireEvent('add', this);
14904 if (typeof(this.events.edit.listeners) != 'undefined') {
14906 this.editicon = this.wrap.createChild(
14907 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
14908 if (this.addicon) {
14909 this.editicon.setStyle('margin-left', '40px');
14911 this.editicon.on('click', function(e) {
14913 // we fire even if inothing is selected..
14914 this.fireEvent('edit', this, this.lastData );
14920 this.keyNav = new Roo.KeyNav(this.inputEl(), {
14921 "up" : function(e){
14922 this.inKeyMode = true;
14926 "down" : function(e){
14927 if(!this.isExpanded()){
14928 this.onTriggerClick();
14930 this.inKeyMode = true;
14935 "enter" : function(e){
14936 // this.onViewClick();
14940 if(this.fireEvent("specialkey", this, e)){
14941 this.onViewClick(false);
14947 "esc" : function(e){
14951 "tab" : function(e){
14954 if(this.fireEvent("specialkey", this, e)){
14955 this.onViewClick(false);
14963 doRelay : function(foo, bar, hname){
14964 if(hname == 'down' || this.scope.isExpanded()){
14965 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14974 this.queryDelay = Math.max(this.queryDelay || 10,
14975 this.mode == 'local' ? 10 : 250);
14978 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14980 if(this.typeAhead){
14981 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14983 if(this.editable !== false){
14984 this.inputEl().on("keyup", this.onKeyUp, this);
14986 if(this.forceSelection){
14987 this.inputEl().on('blur', this.doForce, this);
14991 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14992 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14996 initTickableEvents: function()
15000 if(this.hiddenName){
15002 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15004 this.hiddenField.dom.value =
15005 this.hiddenValue !== undefined ? this.hiddenValue :
15006 this.value !== undefined ? this.value : '';
15008 // prevent input submission
15009 this.el.dom.removeAttribute('name');
15010 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15015 // this.list = this.el.select('ul.dropdown-menu',true).first();
15017 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15018 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15019 if(this.triggerList){
15020 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
15023 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
15024 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
15026 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
15027 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
15029 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
15030 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
15032 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
15033 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
15034 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
15037 this.cancelBtn.hide();
15042 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15043 _this.list.setWidth(lw);
15046 this.list.on('mouseover', this.onViewOver, this);
15047 this.list.on('mousemove', this.onViewMove, this);
15049 this.list.on('scroll', this.onViewScroll, this);
15052 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
15053 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
15056 this.view = new Roo.View(this.list, this.tpl, {
15061 selectedClass: this.selectedClass
15064 //this.view.wrapEl.setDisplayed(false);
15065 this.view.on('click', this.onViewClick, this);
15069 this.store.on('beforeload', this.onBeforeLoad, this);
15070 this.store.on('load', this.onLoad, this);
15071 this.store.on('loadexception', this.onLoadException, this);
15074 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
15075 "up" : function(e){
15076 this.inKeyMode = true;
15080 "down" : function(e){
15081 this.inKeyMode = true;
15085 "enter" : function(e){
15086 if(this.fireEvent("specialkey", this, e)){
15087 this.onViewClick(false);
15093 "esc" : function(e){
15094 this.onTickableFooterButtonClick(e, false, false);
15097 "tab" : function(e){
15098 this.fireEvent("specialkey", this, e);
15100 this.onTickableFooterButtonClick(e, false, false);
15107 doRelay : function(e, fn, key){
15108 if(this.scope.isExpanded()){
15109 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15118 this.queryDelay = Math.max(this.queryDelay || 10,
15119 this.mode == 'local' ? 10 : 250);
15122 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15124 if(this.typeAhead){
15125 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15128 if(this.editable !== false){
15129 this.tickableInputEl().on("keyup", this.onKeyUp, this);
15132 this.indicator = this.indicatorEl();
15134 if(this.indicator){
15135 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
15136 this.indicator.hide();
15141 onDestroy : function(){
15143 this.view.setStore(null);
15144 this.view.el.removeAllListeners();
15145 this.view.el.remove();
15146 this.view.purgeListeners();
15149 this.list.dom.innerHTML = '';
15153 this.store.un('beforeload', this.onBeforeLoad, this);
15154 this.store.un('load', this.onLoad, this);
15155 this.store.un('loadexception', this.onLoadException, this);
15157 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
15161 fireKey : function(e){
15162 if(e.isNavKeyPress() && !this.list.isVisible()){
15163 this.fireEvent("specialkey", this, e);
15168 onResize: function(w, h){
15169 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
15171 // if(typeof w != 'number'){
15172 // // we do not handle it!?!?
15175 // var tw = this.trigger.getWidth();
15176 // // tw += this.addicon ? this.addicon.getWidth() : 0;
15177 // // tw += this.editicon ? this.editicon.getWidth() : 0;
15179 // this.inputEl().setWidth( this.adjustWidth('input', x));
15181 // //this.trigger.setStyle('left', x+'px');
15183 // if(this.list && this.listWidth === undefined){
15184 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
15185 // this.list.setWidth(lw);
15186 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15194 * Allow or prevent the user from directly editing the field text. If false is passed,
15195 * the user will only be able to select from the items defined in the dropdown list. This method
15196 * is the runtime equivalent of setting the 'editable' config option at config time.
15197 * @param {Boolean} value True to allow the user to directly edit the field text
15199 setEditable : function(value){
15200 if(value == this.editable){
15203 this.editable = value;
15205 this.inputEl().dom.setAttribute('readOnly', true);
15206 this.inputEl().on('mousedown', this.onTriggerClick, this);
15207 this.inputEl().addClass('x-combo-noedit');
15209 this.inputEl().dom.setAttribute('readOnly', false);
15210 this.inputEl().un('mousedown', this.onTriggerClick, this);
15211 this.inputEl().removeClass('x-combo-noedit');
15217 onBeforeLoad : function(combo,opts){
15218 if(!this.hasFocus){
15222 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
15224 this.restrictHeight();
15225 this.selectedIndex = -1;
15229 onLoad : function(){
15231 this.hasQuery = false;
15233 if(!this.hasFocus){
15237 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15238 this.loading.hide();
15241 if(this.store.getCount() > 0){
15244 this.restrictHeight();
15245 if(this.lastQuery == this.allQuery){
15246 if(this.editable && !this.tickable){
15247 this.inputEl().dom.select();
15251 !this.selectByValue(this.value, true) &&
15254 !this.store.lastOptions ||
15255 typeof(this.store.lastOptions.add) == 'undefined' ||
15256 this.store.lastOptions.add != true
15259 this.select(0, true);
15262 if(this.autoFocus){
15265 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
15266 this.taTask.delay(this.typeAheadDelay);
15270 this.onEmptyResults();
15276 onLoadException : function()
15278 this.hasQuery = false;
15280 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15281 this.loading.hide();
15284 if(this.tickable && this.editable){
15289 // only causes errors at present
15290 //Roo.log(this.store.reader.jsonData);
15291 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
15293 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
15299 onTypeAhead : function(){
15300 if(this.store.getCount() > 0){
15301 var r = this.store.getAt(0);
15302 var newValue = r.data[this.displayField];
15303 var len = newValue.length;
15304 var selStart = this.getRawValue().length;
15306 if(selStart != len){
15307 this.setRawValue(newValue);
15308 this.selectText(selStart, newValue.length);
15314 onSelect : function(record, index){
15316 if(this.fireEvent('beforeselect', this, record, index) !== false){
15318 this.setFromData(index > -1 ? record.data : false);
15321 this.fireEvent('select', this, record, index);
15326 * Returns the currently selected field value or empty string if no value is set.
15327 * @return {String} value The selected value
15329 getValue : function()
15331 if(Roo.isIOS && this.useNativeIOS){
15332 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
15336 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
15339 if(this.valueField){
15340 return typeof this.value != 'undefined' ? this.value : '';
15342 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
15346 getRawValue : function()
15348 if(Roo.isIOS && this.useNativeIOS){
15349 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
15352 var v = this.inputEl().getValue();
15358 * Clears any text/value currently set in the field
15360 clearValue : function(){
15362 if(this.hiddenField){
15363 this.hiddenField.dom.value = '';
15366 this.setRawValue('');
15367 this.lastSelectionText = '';
15368 this.lastData = false;
15370 var close = this.closeTriggerEl();
15381 * Sets the specified value into the field. If the value finds a match, the corresponding record text
15382 * will be displayed in the field. If the value does not match the data value of an existing item,
15383 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
15384 * Otherwise the field will be blank (although the value will still be set).
15385 * @param {String} value The value to match
15387 setValue : function(v)
15389 if(Roo.isIOS && this.useNativeIOS){
15390 this.setIOSValue(v);
15400 if(this.valueField){
15401 var r = this.findRecord(this.valueField, v);
15403 text = r.data[this.displayField];
15404 }else if(this.valueNotFoundText !== undefined){
15405 text = this.valueNotFoundText;
15408 this.lastSelectionText = text;
15409 if(this.hiddenField){
15410 this.hiddenField.dom.value = v;
15412 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
15415 var close = this.closeTriggerEl();
15418 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
15424 * @property {Object} the last set data for the element
15429 * Sets the value of the field based on a object which is related to the record format for the store.
15430 * @param {Object} value the value to set as. or false on reset?
15432 setFromData : function(o){
15439 var dv = ''; // display value
15440 var vv = ''; // value value..
15442 if (this.displayField) {
15443 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15445 // this is an error condition!!!
15446 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15449 if(this.valueField){
15450 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
15453 var close = this.closeTriggerEl();
15456 if(dv.length || vv * 1 > 0){
15458 this.blockFocus=true;
15464 if(this.hiddenField){
15465 this.hiddenField.dom.value = vv;
15467 this.lastSelectionText = dv;
15468 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
15472 // no hidden field.. - we store the value in 'value', but still display
15473 // display field!!!!
15474 this.lastSelectionText = dv;
15475 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
15482 reset : function(){
15483 // overridden so that last data is reset..
15490 this.setValue(this.originalValue);
15491 //this.clearInvalid();
15492 this.lastData = false;
15494 this.view.clearSelections();
15500 findRecord : function(prop, value){
15502 if(this.store.getCount() > 0){
15503 this.store.each(function(r){
15504 if(r.data[prop] == value){
15514 getName: function()
15516 // returns hidden if it's set..
15517 if (!this.rendered) {return ''};
15518 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
15522 onViewMove : function(e, t){
15523 this.inKeyMode = false;
15527 onViewOver : function(e, t){
15528 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
15531 var item = this.view.findItemFromChild(t);
15534 var index = this.view.indexOf(item);
15535 this.select(index, false);
15540 onViewClick : function(view, doFocus, el, e)
15542 var index = this.view.getSelectedIndexes()[0];
15544 var r = this.store.getAt(index);
15548 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
15555 Roo.each(this.tickItems, function(v,k){
15557 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
15559 _this.tickItems.splice(k, 1);
15561 if(typeof(e) == 'undefined' && view == false){
15562 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
15574 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
15575 this.tickItems.push(r.data);
15578 if(typeof(e) == 'undefined' && view == false){
15579 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
15586 this.onSelect(r, index);
15588 if(doFocus !== false && !this.blockFocus){
15589 this.inputEl().focus();
15594 restrictHeight : function(){
15595 //this.innerList.dom.style.height = '';
15596 //var inner = this.innerList.dom;
15597 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
15598 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
15599 //this.list.beginUpdate();
15600 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
15601 this.list.alignTo(this.inputEl(), this.listAlign);
15602 this.list.alignTo(this.inputEl(), this.listAlign);
15603 //this.list.endUpdate();
15607 onEmptyResults : function(){
15609 if(this.tickable && this.editable){
15610 this.hasFocus = false;
15611 this.restrictHeight();
15619 * Returns true if the dropdown list is expanded, else false.
15621 isExpanded : function(){
15622 return this.list.isVisible();
15626 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
15627 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
15628 * @param {String} value The data value of the item to select
15629 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
15630 * selected item if it is not currently in view (defaults to true)
15631 * @return {Boolean} True if the value matched an item in the list, else false
15633 selectByValue : function(v, scrollIntoView){
15634 if(v !== undefined && v !== null){
15635 var r = this.findRecord(this.valueField || this.displayField, v);
15637 this.select(this.store.indexOf(r), scrollIntoView);
15645 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
15646 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
15647 * @param {Number} index The zero-based index of the list item to select
15648 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
15649 * selected item if it is not currently in view (defaults to true)
15651 select : function(index, scrollIntoView){
15652 this.selectedIndex = index;
15653 this.view.select(index);
15654 if(scrollIntoView !== false){
15655 var el = this.view.getNode(index);
15657 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
15660 this.list.scrollChildIntoView(el, false);
15666 selectNext : function(){
15667 var ct = this.store.getCount();
15669 if(this.selectedIndex == -1){
15671 }else if(this.selectedIndex < ct-1){
15672 this.select(this.selectedIndex+1);
15678 selectPrev : function(){
15679 var ct = this.store.getCount();
15681 if(this.selectedIndex == -1){
15683 }else if(this.selectedIndex != 0){
15684 this.select(this.selectedIndex-1);
15690 onKeyUp : function(e){
15691 if(this.editable !== false && !e.isSpecialKey()){
15692 this.lastKey = e.getKey();
15693 this.dqTask.delay(this.queryDelay);
15698 validateBlur : function(){
15699 return !this.list || !this.list.isVisible();
15703 initQuery : function(){
15705 var v = this.getRawValue();
15707 if(this.tickable && this.editable){
15708 v = this.tickableInputEl().getValue();
15715 doForce : function(){
15716 if(this.inputEl().dom.value.length > 0){
15717 this.inputEl().dom.value =
15718 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
15724 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
15725 * query allowing the query action to be canceled if needed.
15726 * @param {String} query The SQL query to execute
15727 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
15728 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
15729 * saved in the current store (defaults to false)
15731 doQuery : function(q, forceAll){
15733 if(q === undefined || q === null){
15738 forceAll: forceAll,
15742 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
15747 forceAll = qe.forceAll;
15748 if(forceAll === true || (q.length >= this.minChars)){
15750 this.hasQuery = true;
15752 if(this.lastQuery != q || this.alwaysQuery){
15753 this.lastQuery = q;
15754 if(this.mode == 'local'){
15755 this.selectedIndex = -1;
15757 this.store.clearFilter();
15760 if(this.specialFilter){
15761 this.fireEvent('specialfilter', this);
15766 this.store.filter(this.displayField, q);
15769 this.store.fireEvent("datachanged", this.store);
15776 this.store.baseParams[this.queryParam] = q;
15778 var options = {params : this.getParams(q)};
15781 options.add = true;
15782 options.params.start = this.page * this.pageSize;
15785 this.store.load(options);
15788 * this code will make the page width larger, at the beginning, the list not align correctly,
15789 * we should expand the list on onLoad
15790 * so command out it
15795 this.selectedIndex = -1;
15800 this.loadNext = false;
15804 getParams : function(q){
15806 //p[this.queryParam] = q;
15810 p.limit = this.pageSize;
15816 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
15818 collapse : function(){
15819 if(!this.isExpanded()){
15825 this.hasFocus = false;
15829 this.cancelBtn.hide();
15830 this.trigger.show();
15833 this.tickableInputEl().dom.value = '';
15834 this.tickableInputEl().blur();
15839 Roo.get(document).un('mousedown', this.collapseIf, this);
15840 Roo.get(document).un('mousewheel', this.collapseIf, this);
15841 if (!this.editable) {
15842 Roo.get(document).un('keydown', this.listKeyPress, this);
15844 this.fireEvent('collapse', this);
15850 collapseIf : function(e){
15851 var in_combo = e.within(this.el);
15852 var in_list = e.within(this.list);
15853 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
15855 if (in_combo || in_list || is_list) {
15856 //e.stopPropagation();
15861 this.onTickableFooterButtonClick(e, false, false);
15869 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
15871 expand : function(){
15873 if(this.isExpanded() || !this.hasFocus){
15877 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
15878 this.list.setWidth(lw);
15884 this.restrictHeight();
15888 this.tickItems = Roo.apply([], this.item);
15891 this.cancelBtn.show();
15892 this.trigger.hide();
15895 this.tickableInputEl().focus();
15900 Roo.get(document).on('mousedown', this.collapseIf, this);
15901 Roo.get(document).on('mousewheel', this.collapseIf, this);
15902 if (!this.editable) {
15903 Roo.get(document).on('keydown', this.listKeyPress, this);
15906 this.fireEvent('expand', this);
15910 // Implements the default empty TriggerField.onTriggerClick function
15911 onTriggerClick : function(e)
15913 Roo.log('trigger click');
15915 if(this.disabled || !this.triggerList){
15920 this.loadNext = false;
15922 if(this.isExpanded()){
15924 if (!this.blockFocus) {
15925 this.inputEl().focus();
15929 this.hasFocus = true;
15930 if(this.triggerAction == 'all') {
15931 this.doQuery(this.allQuery, true);
15933 this.doQuery(this.getRawValue());
15935 if (!this.blockFocus) {
15936 this.inputEl().focus();
15941 onTickableTriggerClick : function(e)
15948 this.loadNext = false;
15949 this.hasFocus = true;
15951 if(this.triggerAction == 'all') {
15952 this.doQuery(this.allQuery, true);
15954 this.doQuery(this.getRawValue());
15958 onSearchFieldClick : function(e)
15960 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
15961 this.onTickableFooterButtonClick(e, false, false);
15965 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
15970 this.loadNext = false;
15971 this.hasFocus = true;
15973 if(this.triggerAction == 'all') {
15974 this.doQuery(this.allQuery, true);
15976 this.doQuery(this.getRawValue());
15980 listKeyPress : function(e)
15982 //Roo.log('listkeypress');
15983 // scroll to first matching element based on key pres..
15984 if (e.isSpecialKey()) {
15987 var k = String.fromCharCode(e.getKey()).toUpperCase();
15990 var csel = this.view.getSelectedNodes();
15991 var cselitem = false;
15993 var ix = this.view.indexOf(csel[0]);
15994 cselitem = this.store.getAt(ix);
15995 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
16001 this.store.each(function(v) {
16003 // start at existing selection.
16004 if (cselitem.id == v.id) {
16010 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
16011 match = this.store.indexOf(v);
16017 if (match === false) {
16018 return true; // no more action?
16021 this.view.select(match);
16022 var sn = Roo.get(this.view.getSelectedNodes()[0]);
16023 sn.scrollIntoView(sn.dom.parentNode, false);
16026 onViewScroll : function(e, t){
16028 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){
16032 this.hasQuery = true;
16034 this.loading = this.list.select('.loading', true).first();
16036 if(this.loading === null){
16037 this.list.createChild({
16039 cls: 'loading roo-select2-more-results roo-select2-active',
16040 html: 'Loading more results...'
16043 this.loading = this.list.select('.loading', true).first();
16045 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
16047 this.loading.hide();
16050 this.loading.show();
16055 this.loadNext = true;
16057 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
16062 addItem : function(o)
16064 var dv = ''; // display value
16066 if (this.displayField) {
16067 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16069 // this is an error condition!!!
16070 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16077 var choice = this.choices.createChild({
16079 cls: 'roo-select2-search-choice',
16088 cls: 'roo-select2-search-choice-close fa fa-times',
16093 }, this.searchField);
16095 var close = choice.select('a.roo-select2-search-choice-close', true).first();
16097 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
16105 this.inputEl().dom.value = '';
16110 onRemoveItem : function(e, _self, o)
16112 e.preventDefault();
16114 this.lastItem = Roo.apply([], this.item);
16116 var index = this.item.indexOf(o.data) * 1;
16119 Roo.log('not this item?!');
16123 this.item.splice(index, 1);
16128 this.fireEvent('remove', this, e);
16134 syncValue : function()
16136 if(!this.item.length){
16143 Roo.each(this.item, function(i){
16144 if(_this.valueField){
16145 value.push(i[_this.valueField]);
16152 this.value = value.join(',');
16154 if(this.hiddenField){
16155 this.hiddenField.dom.value = this.value;
16158 this.store.fireEvent("datachanged", this.store);
16163 clearItem : function()
16165 if(!this.multiple){
16171 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
16179 if(this.tickable && !Roo.isTouch){
16180 this.view.refresh();
16184 inputEl: function ()
16186 if(Roo.isIOS && this.useNativeIOS){
16187 return this.el.select('select.roo-ios-select', true).first();
16190 if(Roo.isTouch && this.mobileTouchView){
16191 return this.el.select('input.form-control',true).first();
16195 return this.searchField;
16198 return this.el.select('input.form-control',true).first();
16201 onTickableFooterButtonClick : function(e, btn, el)
16203 e.preventDefault();
16205 this.lastItem = Roo.apply([], this.item);
16207 if(btn && btn.name == 'cancel'){
16208 this.tickItems = Roo.apply([], this.item);
16217 Roo.each(this.tickItems, function(o){
16225 validate : function()
16227 if(this.getVisibilityEl().hasClass('hidden')){
16231 var v = this.getRawValue();
16234 v = this.getValue();
16237 if(this.disabled || this.allowBlank || v.length){
16242 this.markInvalid();
16246 tickableInputEl : function()
16248 if(!this.tickable || !this.editable){
16249 return this.inputEl();
16252 return this.inputEl().select('.roo-select2-search-field-input', true).first();
16256 getAutoCreateTouchView : function()
16261 cls: 'form-group' //input-group
16267 type : this.inputType,
16268 cls : 'form-control x-combo-noedit',
16269 autocomplete: 'new-password',
16270 placeholder : this.placeholder || '',
16275 input.name = this.name;
16279 input.cls += ' input-' + this.size;
16282 if (this.disabled) {
16283 input.disabled = true;
16294 inputblock.cls += ' input-group';
16296 inputblock.cn.unshift({
16298 cls : 'input-group-addon input-group-prepend input-group-text',
16303 if(this.removable && !this.multiple){
16304 inputblock.cls += ' roo-removable';
16306 inputblock.cn.push({
16309 cls : 'roo-combo-removable-btn close'
16313 if(this.hasFeedback && !this.allowBlank){
16315 inputblock.cls += ' has-feedback';
16317 inputblock.cn.push({
16319 cls: 'glyphicon form-control-feedback'
16326 inputblock.cls += (this.before) ? '' : ' input-group';
16328 inputblock.cn.push({
16330 cls : 'input-group-addon input-group-append input-group-text',
16336 var ibwrap = inputblock;
16341 cls: 'roo-select2-choices',
16345 cls: 'roo-select2-search-field',
16358 cls: 'roo-select2-container input-group roo-touchview-combobox ',
16363 cls: 'form-hidden-field'
16369 if(!this.multiple && this.showToggleBtn){
16375 if (this.caret != false) {
16378 cls: 'fa fa-' + this.caret
16385 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
16387 Roo.bootstrap.version == 3 ? caret : '',
16390 cls: 'combobox-clear',
16404 combobox.cls += ' roo-select2-container-multi';
16407 var align = this.labelAlign || this.parentLabelAlign();
16409 if (align ==='left' && this.fieldLabel.length) {
16414 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
16415 tooltip : 'This field is required'
16419 cls : 'control-label col-form-label',
16420 html : this.fieldLabel
16431 var labelCfg = cfg.cn[1];
16432 var contentCfg = cfg.cn[2];
16435 if(this.indicatorpos == 'right'){
16440 cls : 'control-label col-form-label',
16444 html : this.fieldLabel
16448 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
16449 tooltip : 'This field is required'
16462 labelCfg = cfg.cn[0];
16463 contentCfg = cfg.cn[1];
16468 if(this.labelWidth > 12){
16469 labelCfg.style = "width: " + this.labelWidth + 'px';
16472 if(this.labelWidth < 13 && this.labelmd == 0){
16473 this.labelmd = this.labelWidth;
16476 if(this.labellg > 0){
16477 labelCfg.cls += ' col-lg-' + this.labellg;
16478 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
16481 if(this.labelmd > 0){
16482 labelCfg.cls += ' col-md-' + this.labelmd;
16483 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
16486 if(this.labelsm > 0){
16487 labelCfg.cls += ' col-sm-' + this.labelsm;
16488 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
16491 if(this.labelxs > 0){
16492 labelCfg.cls += ' col-xs-' + this.labelxs;
16493 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
16497 } else if ( this.fieldLabel.length) {
16501 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
16502 tooltip : 'This field is required'
16506 cls : 'control-label',
16507 html : this.fieldLabel
16518 if(this.indicatorpos == 'right'){
16522 cls : 'control-label',
16523 html : this.fieldLabel,
16527 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
16528 tooltip : 'This field is required'
16545 var settings = this;
16547 ['xs','sm','md','lg'].map(function(size){
16548 if (settings[size]) {
16549 cfg.cls += ' col-' + size + '-' + settings[size];
16556 initTouchView : function()
16558 this.renderTouchView();
16560 this.touchViewEl.on('scroll', function(){
16561 this.el.dom.scrollTop = 0;
16564 this.originalValue = this.getValue();
16566 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
16568 this.inputEl().on("click", this.showTouchView, this);
16569 if (this.triggerEl) {
16570 this.triggerEl.on("click", this.showTouchView, this);
16574 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
16575 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
16577 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
16579 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
16580 this.store.on('load', this.onTouchViewLoad, this);
16581 this.store.on('loadexception', this.onTouchViewLoadException, this);
16583 if(this.hiddenName){
16585 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
16587 this.hiddenField.dom.value =
16588 this.hiddenValue !== undefined ? this.hiddenValue :
16589 this.value !== undefined ? this.value : '';
16591 this.el.dom.removeAttribute('name');
16592 this.hiddenField.dom.setAttribute('name', this.hiddenName);
16596 this.choices = this.el.select('ul.roo-select2-choices', true).first();
16597 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
16600 if(this.removable && !this.multiple){
16601 var close = this.closeTriggerEl();
16603 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
16604 close.on('click', this.removeBtnClick, this, close);
16608 * fix the bug in Safari iOS8
16610 this.inputEl().on("focus", function(e){
16611 document.activeElement.blur();
16614 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
16621 renderTouchView : function()
16623 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
16624 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16626 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
16627 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16629 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
16630 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16631 this.touchViewBodyEl.setStyle('overflow', 'auto');
16633 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
16634 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16636 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
16637 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16641 showTouchView : function()
16647 this.touchViewHeaderEl.hide();
16649 if(this.modalTitle.length){
16650 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
16651 this.touchViewHeaderEl.show();
16654 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
16655 this.touchViewEl.show();
16657 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
16659 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
16660 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
16662 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
16664 if(this.modalTitle.length){
16665 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
16668 this.touchViewBodyEl.setHeight(bodyHeight);
16672 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
16674 this.touchViewEl.addClass('in');
16677 if(this._touchViewMask){
16678 Roo.get(document.body).addClass("x-body-masked");
16679 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
16680 this._touchViewMask.setStyle('z-index', 10000);
16681 this._touchViewMask.addClass('show');
16684 this.doTouchViewQuery();
16688 hideTouchView : function()
16690 this.touchViewEl.removeClass('in');
16694 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
16696 this.touchViewEl.setStyle('display', 'none');
16699 if(this._touchViewMask){
16700 this._touchViewMask.removeClass('show');
16701 Roo.get(document.body).removeClass("x-body-masked");
16705 setTouchViewValue : function()
16712 Roo.each(this.tickItems, function(o){
16717 this.hideTouchView();
16720 doTouchViewQuery : function()
16729 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
16733 if(!this.alwaysQuery || this.mode == 'local'){
16734 this.onTouchViewLoad();
16741 onTouchViewBeforeLoad : function(combo,opts)
16747 onTouchViewLoad : function()
16749 if(this.store.getCount() < 1){
16750 this.onTouchViewEmptyResults();
16754 this.clearTouchView();
16756 var rawValue = this.getRawValue();
16758 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
16760 this.tickItems = [];
16762 this.store.data.each(function(d, rowIndex){
16763 var row = this.touchViewListGroup.createChild(template);
16765 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
16766 row.addClass(d.data.cls);
16769 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16772 html : d.data[this.displayField]
16775 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
16776 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
16779 row.removeClass('selected');
16780 if(!this.multiple && this.valueField &&
16781 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
16784 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16785 row.addClass('selected');
16788 if(this.multiple && this.valueField &&
16789 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
16793 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16794 this.tickItems.push(d.data);
16797 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
16801 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
16803 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
16805 if(this.modalTitle.length){
16806 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
16809 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
16811 if(this.mobile_restrict_height && listHeight < bodyHeight){
16812 this.touchViewBodyEl.setHeight(listHeight);
16817 if(firstChecked && listHeight > bodyHeight){
16818 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
16823 onTouchViewLoadException : function()
16825 this.hideTouchView();
16828 onTouchViewEmptyResults : function()
16830 this.clearTouchView();
16832 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
16834 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
16838 clearTouchView : function()
16840 this.touchViewListGroup.dom.innerHTML = '';
16843 onTouchViewClick : function(e, el, o)
16845 e.preventDefault();
16848 var rowIndex = o.rowIndex;
16850 var r = this.store.getAt(rowIndex);
16852 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
16854 if(!this.multiple){
16855 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
16856 c.dom.removeAttribute('checked');
16859 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16861 this.setFromData(r.data);
16863 var close = this.closeTriggerEl();
16869 this.hideTouchView();
16871 this.fireEvent('select', this, r, rowIndex);
16876 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
16877 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
16878 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
16882 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16883 this.addItem(r.data);
16884 this.tickItems.push(r.data);
16888 getAutoCreateNativeIOS : function()
16891 cls: 'form-group' //input-group,
16896 cls : 'roo-ios-select'
16900 combobox.name = this.name;
16903 if (this.disabled) {
16904 combobox.disabled = true;
16907 var settings = this;
16909 ['xs','sm','md','lg'].map(function(size){
16910 if (settings[size]) {
16911 cfg.cls += ' col-' + size + '-' + settings[size];
16921 initIOSView : function()
16923 this.store.on('load', this.onIOSViewLoad, this);
16928 onIOSViewLoad : function()
16930 if(this.store.getCount() < 1){
16934 this.clearIOSView();
16936 if(this.allowBlank) {
16938 var default_text = '-- SELECT --';
16940 if(this.placeholder.length){
16941 default_text = this.placeholder;
16944 if(this.emptyTitle.length){
16945 default_text += ' - ' + this.emptyTitle + ' -';
16948 var opt = this.inputEl().createChild({
16951 html : default_text
16955 o[this.valueField] = 0;
16956 o[this.displayField] = default_text;
16958 this.ios_options.push({
16965 this.store.data.each(function(d, rowIndex){
16969 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16970 html = d.data[this.displayField];
16975 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16976 value = d.data[this.valueField];
16985 if(this.value == d.data[this.valueField]){
16986 option['selected'] = true;
16989 var opt = this.inputEl().createChild(option);
16991 this.ios_options.push({
16998 this.inputEl().on('change', function(){
16999 this.fireEvent('select', this);
17004 clearIOSView: function()
17006 this.inputEl().dom.innerHTML = '';
17008 this.ios_options = [];
17011 setIOSValue: function(v)
17015 if(!this.ios_options){
17019 Roo.each(this.ios_options, function(opts){
17021 opts.el.dom.removeAttribute('selected');
17023 if(opts.data[this.valueField] != v){
17027 opts.el.dom.setAttribute('selected', true);
17033 * @cfg {Boolean} grow
17037 * @cfg {Number} growMin
17041 * @cfg {Number} growMax
17050 Roo.apply(Roo.bootstrap.ComboBox, {
17054 cls: 'modal-header',
17076 cls: 'list-group-item',
17080 cls: 'roo-combobox-list-group-item-value'
17084 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
17098 listItemCheckbox : {
17100 cls: 'list-group-item',
17104 cls: 'roo-combobox-list-group-item-value'
17108 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
17124 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
17129 cls: 'modal-footer',
17137 cls: 'col-xs-6 text-left',
17140 cls: 'btn btn-danger roo-touch-view-cancel',
17146 cls: 'col-xs-6 text-right',
17149 cls: 'btn btn-success roo-touch-view-ok',
17160 Roo.apply(Roo.bootstrap.ComboBox, {
17162 touchViewTemplate : {
17164 cls: 'modal fade roo-combobox-touch-view',
17168 cls: 'modal-dialog',
17169 style : 'position:fixed', // we have to fix position....
17173 cls: 'modal-content',
17175 Roo.bootstrap.ComboBox.header,
17176 Roo.bootstrap.ComboBox.body,
17177 Roo.bootstrap.ComboBox.footer
17186 * Ext JS Library 1.1.1
17187 * Copyright(c) 2006-2007, Ext JS, LLC.
17189 * Originally Released Under LGPL - original licence link has changed is not relivant.
17192 * <script type="text/javascript">
17197 * @extends Roo.util.Observable
17198 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
17199 * This class also supports single and multi selection modes. <br>
17200 * Create a data model bound view:
17202 var store = new Roo.data.Store(...);
17204 var view = new Roo.View({
17206 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
17208 singleSelect: true,
17209 selectedClass: "ydataview-selected",
17213 // listen for node click?
17214 view.on("click", function(vw, index, node, e){
17215 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
17219 dataModel.load("foobar.xml");
17221 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
17223 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
17224 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
17226 * Note: old style constructor is still suported (container, template, config)
17229 * Create a new View
17230 * @param {Object} config The config object
17233 Roo.View = function(config, depreciated_tpl, depreciated_config){
17235 this.parent = false;
17237 if (typeof(depreciated_tpl) == 'undefined') {
17238 // new way.. - universal constructor.
17239 Roo.apply(this, config);
17240 this.el = Roo.get(this.el);
17243 this.el = Roo.get(config);
17244 this.tpl = depreciated_tpl;
17245 Roo.apply(this, depreciated_config);
17247 this.wrapEl = this.el.wrap().wrap();
17248 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
17251 if(typeof(this.tpl) == "string"){
17252 this.tpl = new Roo.Template(this.tpl);
17254 // support xtype ctors..
17255 this.tpl = new Roo.factory(this.tpl, Roo);
17259 this.tpl.compile();
17264 * @event beforeclick
17265 * Fires before a click is processed. Returns false to cancel the default action.
17266 * @param {Roo.View} this
17267 * @param {Number} index The index of the target node
17268 * @param {HTMLElement} node The target node
17269 * @param {Roo.EventObject} e The raw event object
17271 "beforeclick" : true,
17274 * Fires when a template node is clicked.
17275 * @param {Roo.View} this
17276 * @param {Number} index The index of the target node
17277 * @param {HTMLElement} node The target node
17278 * @param {Roo.EventObject} e The raw event object
17283 * Fires when a template node is double clicked.
17284 * @param {Roo.View} this
17285 * @param {Number} index The index of the target node
17286 * @param {HTMLElement} node The target node
17287 * @param {Roo.EventObject} e The raw event object
17291 * @event contextmenu
17292 * Fires when a template node is right clicked.
17293 * @param {Roo.View} this
17294 * @param {Number} index The index of the target node
17295 * @param {HTMLElement} node The target node
17296 * @param {Roo.EventObject} e The raw event object
17298 "contextmenu" : true,
17300 * @event selectionchange
17301 * Fires when the selected nodes change.
17302 * @param {Roo.View} this
17303 * @param {Array} selections Array of the selected nodes
17305 "selectionchange" : true,
17308 * @event beforeselect
17309 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
17310 * @param {Roo.View} this
17311 * @param {HTMLElement} node The node to be selected
17312 * @param {Array} selections Array of currently selected nodes
17314 "beforeselect" : true,
17316 * @event preparedata
17317 * Fires on every row to render, to allow you to change the data.
17318 * @param {Roo.View} this
17319 * @param {Object} data to be rendered (change this)
17321 "preparedata" : true
17329 "click": this.onClick,
17330 "dblclick": this.onDblClick,
17331 "contextmenu": this.onContextMenu,
17335 this.selections = [];
17337 this.cmp = new Roo.CompositeElementLite([]);
17339 this.store = Roo.factory(this.store, Roo.data);
17340 this.setStore(this.store, true);
17343 if ( this.footer && this.footer.xtype) {
17345 var fctr = this.wrapEl.appendChild(document.createElement("div"));
17347 this.footer.dataSource = this.store;
17348 this.footer.container = fctr;
17349 this.footer = Roo.factory(this.footer, Roo);
17350 fctr.insertFirst(this.el);
17352 // this is a bit insane - as the paging toolbar seems to detach the el..
17353 // dom.parentNode.parentNode.parentNode
17354 // they get detached?
17358 Roo.View.superclass.constructor.call(this);
17363 Roo.extend(Roo.View, Roo.util.Observable, {
17366 * @cfg {Roo.data.Store} store Data store to load data from.
17371 * @cfg {String|Roo.Element} el The container element.
17376 * @cfg {String|Roo.Template} tpl The template used by this View
17380 * @cfg {String} dataName the named area of the template to use as the data area
17381 * Works with domtemplates roo-name="name"
17385 * @cfg {String} selectedClass The css class to add to selected nodes
17387 selectedClass : "x-view-selected",
17389 * @cfg {String} emptyText The empty text to show when nothing is loaded.
17394 * @cfg {String} text to display on mask (default Loading)
17398 * @cfg {Boolean} multiSelect Allow multiple selection
17400 multiSelect : false,
17402 * @cfg {Boolean} singleSelect Allow single selection
17404 singleSelect: false,
17407 * @cfg {Boolean} toggleSelect - selecting
17409 toggleSelect : false,
17412 * @cfg {Boolean} tickable - selecting
17417 * Returns the element this view is bound to.
17418 * @return {Roo.Element}
17420 getEl : function(){
17421 return this.wrapEl;
17427 * Refreshes the view. - called by datachanged on the store. - do not call directly.
17429 refresh : function(){
17430 //Roo.log('refresh');
17433 // if we are using something like 'domtemplate', then
17434 // the what gets used is:
17435 // t.applySubtemplate(NAME, data, wrapping data..)
17436 // the outer template then get' applied with
17437 // the store 'extra data'
17438 // and the body get's added to the
17439 // roo-name="data" node?
17440 // <span class='roo-tpl-{name}'></span> ?????
17444 this.clearSelections();
17445 this.el.update("");
17447 var records = this.store.getRange();
17448 if(records.length < 1) {
17450 // is this valid?? = should it render a template??
17452 this.el.update(this.emptyText);
17456 if (this.dataName) {
17457 this.el.update(t.apply(this.store.meta)); //????
17458 el = this.el.child('.roo-tpl-' + this.dataName);
17461 for(var i = 0, len = records.length; i < len; i++){
17462 var data = this.prepareData(records[i].data, i, records[i]);
17463 this.fireEvent("preparedata", this, data, i, records[i]);
17465 var d = Roo.apply({}, data);
17468 Roo.apply(d, {'roo-id' : Roo.id()});
17472 Roo.each(this.parent.item, function(item){
17473 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
17476 Roo.apply(d, {'roo-data-checked' : 'checked'});
17480 html[html.length] = Roo.util.Format.trim(
17482 t.applySubtemplate(this.dataName, d, this.store.meta) :
17489 el.update(html.join(""));
17490 this.nodes = el.dom.childNodes;
17491 this.updateIndexes(0);
17496 * Function to override to reformat the data that is sent to
17497 * the template for each node.
17498 * DEPRICATED - use the preparedata event handler.
17499 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
17500 * a JSON object for an UpdateManager bound view).
17502 prepareData : function(data, index, record)
17504 this.fireEvent("preparedata", this, data, index, record);
17508 onUpdate : function(ds, record){
17509 // Roo.log('on update');
17510 this.clearSelections();
17511 var index = this.store.indexOf(record);
17512 var n = this.nodes[index];
17513 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
17514 n.parentNode.removeChild(n);
17515 this.updateIndexes(index, index);
17521 onAdd : function(ds, records, index)
17523 //Roo.log(['on Add', ds, records, index] );
17524 this.clearSelections();
17525 if(this.nodes.length == 0){
17529 var n = this.nodes[index];
17530 for(var i = 0, len = records.length; i < len; i++){
17531 var d = this.prepareData(records[i].data, i, records[i]);
17533 this.tpl.insertBefore(n, d);
17536 this.tpl.append(this.el, d);
17539 this.updateIndexes(index);
17542 onRemove : function(ds, record, index){
17543 // Roo.log('onRemove');
17544 this.clearSelections();
17545 var el = this.dataName ?
17546 this.el.child('.roo-tpl-' + this.dataName) :
17549 el.dom.removeChild(this.nodes[index]);
17550 this.updateIndexes(index);
17554 * Refresh an individual node.
17555 * @param {Number} index
17557 refreshNode : function(index){
17558 this.onUpdate(this.store, this.store.getAt(index));
17561 updateIndexes : function(startIndex, endIndex){
17562 var ns = this.nodes;
17563 startIndex = startIndex || 0;
17564 endIndex = endIndex || ns.length - 1;
17565 for(var i = startIndex; i <= endIndex; i++){
17566 ns[i].nodeIndex = i;
17571 * Changes the data store this view uses and refresh the view.
17572 * @param {Store} store
17574 setStore : function(store, initial){
17575 if(!initial && this.store){
17576 this.store.un("datachanged", this.refresh);
17577 this.store.un("add", this.onAdd);
17578 this.store.un("remove", this.onRemove);
17579 this.store.un("update", this.onUpdate);
17580 this.store.un("clear", this.refresh);
17581 this.store.un("beforeload", this.onBeforeLoad);
17582 this.store.un("load", this.onLoad);
17583 this.store.un("loadexception", this.onLoad);
17587 store.on("datachanged", this.refresh, this);
17588 store.on("add", this.onAdd, this);
17589 store.on("remove", this.onRemove, this);
17590 store.on("update", this.onUpdate, this);
17591 store.on("clear", this.refresh, this);
17592 store.on("beforeload", this.onBeforeLoad, this);
17593 store.on("load", this.onLoad, this);
17594 store.on("loadexception", this.onLoad, this);
17602 * onbeforeLoad - masks the loading area.
17605 onBeforeLoad : function(store,opts)
17607 //Roo.log('onBeforeLoad');
17609 this.el.update("");
17611 this.el.mask(this.mask ? this.mask : "Loading" );
17613 onLoad : function ()
17620 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
17621 * @param {HTMLElement} node
17622 * @return {HTMLElement} The template node
17624 findItemFromChild : function(node){
17625 var el = this.dataName ?
17626 this.el.child('.roo-tpl-' + this.dataName,true) :
17629 if(!node || node.parentNode == el){
17632 var p = node.parentNode;
17633 while(p && p != el){
17634 if(p.parentNode == el){
17643 onClick : function(e){
17644 var item = this.findItemFromChild(e.getTarget());
17646 var index = this.indexOf(item);
17647 if(this.onItemClick(item, index, e) !== false){
17648 this.fireEvent("click", this, index, item, e);
17651 this.clearSelections();
17656 onContextMenu : function(e){
17657 var item = this.findItemFromChild(e.getTarget());
17659 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
17664 onDblClick : function(e){
17665 var item = this.findItemFromChild(e.getTarget());
17667 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
17671 onItemClick : function(item, index, e)
17673 if(this.fireEvent("beforeclick", this, index, item, e) === false){
17676 if (this.toggleSelect) {
17677 var m = this.isSelected(item) ? 'unselect' : 'select';
17680 _t[m](item, true, false);
17683 if(this.multiSelect || this.singleSelect){
17684 if(this.multiSelect && e.shiftKey && this.lastSelection){
17685 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
17687 this.select(item, this.multiSelect && e.ctrlKey);
17688 this.lastSelection = item;
17691 if(!this.tickable){
17692 e.preventDefault();
17700 * Get the number of selected nodes.
17703 getSelectionCount : function(){
17704 return this.selections.length;
17708 * Get the currently selected nodes.
17709 * @return {Array} An array of HTMLElements
17711 getSelectedNodes : function(){
17712 return this.selections;
17716 * Get the indexes of the selected nodes.
17719 getSelectedIndexes : function(){
17720 var indexes = [], s = this.selections;
17721 for(var i = 0, len = s.length; i < len; i++){
17722 indexes.push(s[i].nodeIndex);
17728 * Clear all selections
17729 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
17731 clearSelections : function(suppressEvent){
17732 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
17733 this.cmp.elements = this.selections;
17734 this.cmp.removeClass(this.selectedClass);
17735 this.selections = [];
17736 if(!suppressEvent){
17737 this.fireEvent("selectionchange", this, this.selections);
17743 * Returns true if the passed node is selected
17744 * @param {HTMLElement/Number} node The node or node index
17745 * @return {Boolean}
17747 isSelected : function(node){
17748 var s = this.selections;
17752 node = this.getNode(node);
17753 return s.indexOf(node) !== -1;
17758 * @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
17759 * @param {Boolean} keepExisting (optional) true to keep existing selections
17760 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
17762 select : function(nodeInfo, keepExisting, suppressEvent){
17763 if(nodeInfo instanceof Array){
17765 this.clearSelections(true);
17767 for(var i = 0, len = nodeInfo.length; i < len; i++){
17768 this.select(nodeInfo[i], true, true);
17772 var node = this.getNode(nodeInfo);
17773 if(!node || this.isSelected(node)){
17774 return; // already selected.
17777 this.clearSelections(true);
17780 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
17781 Roo.fly(node).addClass(this.selectedClass);
17782 this.selections.push(node);
17783 if(!suppressEvent){
17784 this.fireEvent("selectionchange", this, this.selections);
17792 * @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
17793 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
17794 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
17796 unselect : function(nodeInfo, keepExisting, suppressEvent)
17798 if(nodeInfo instanceof Array){
17799 Roo.each(this.selections, function(s) {
17800 this.unselect(s, nodeInfo);
17804 var node = this.getNode(nodeInfo);
17805 if(!node || !this.isSelected(node)){
17806 //Roo.log("not selected");
17807 return; // not selected.
17811 Roo.each(this.selections, function(s) {
17813 Roo.fly(node).removeClass(this.selectedClass);
17820 this.selections= ns;
17821 this.fireEvent("selectionchange", this, this.selections);
17825 * Gets a template node.
17826 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
17827 * @return {HTMLElement} The node or null if it wasn't found
17829 getNode : function(nodeInfo){
17830 if(typeof nodeInfo == "string"){
17831 return document.getElementById(nodeInfo);
17832 }else if(typeof nodeInfo == "number"){
17833 return this.nodes[nodeInfo];
17839 * Gets a range template nodes.
17840 * @param {Number} startIndex
17841 * @param {Number} endIndex
17842 * @return {Array} An array of nodes
17844 getNodes : function(start, end){
17845 var ns = this.nodes;
17846 start = start || 0;
17847 end = typeof end == "undefined" ? ns.length - 1 : end;
17850 for(var i = start; i <= end; i++){
17854 for(var i = start; i >= end; i--){
17862 * Finds the index of the passed node
17863 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
17864 * @return {Number} The index of the node or -1
17866 indexOf : function(node){
17867 node = this.getNode(node);
17868 if(typeof node.nodeIndex == "number"){
17869 return node.nodeIndex;
17871 var ns = this.nodes;
17872 for(var i = 0, len = ns.length; i < len; i++){
17883 * based on jquery fullcalendar
17887 Roo.bootstrap = Roo.bootstrap || {};
17889 * @class Roo.bootstrap.Calendar
17890 * @extends Roo.bootstrap.Component
17891 * Bootstrap Calendar class
17892 * @cfg {Boolean} loadMask (true|false) default false
17893 * @cfg {Object} header generate the user specific header of the calendar, default false
17896 * Create a new Container
17897 * @param {Object} config The config object
17902 Roo.bootstrap.Calendar = function(config){
17903 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
17907 * Fires when a date is selected
17908 * @param {DatePicker} this
17909 * @param {Date} date The selected date
17913 * @event monthchange
17914 * Fires when the displayed month changes
17915 * @param {DatePicker} this
17916 * @param {Date} date The selected month
17918 'monthchange': true,
17920 * @event evententer
17921 * Fires when mouse over an event
17922 * @param {Calendar} this
17923 * @param {event} Event
17925 'evententer': true,
17927 * @event eventleave
17928 * Fires when the mouse leaves an
17929 * @param {Calendar} this
17932 'eventleave': true,
17934 * @event eventclick
17935 * Fires when the mouse click an
17936 * @param {Calendar} this
17945 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
17948 * @cfg {Number} startDay
17949 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
17957 getAutoCreate : function(){
17960 var fc_button = function(name, corner, style, content ) {
17961 return Roo.apply({},{
17963 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
17965 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
17968 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17979 style : 'width:100%',
17986 cls : 'fc-header-left',
17988 fc_button('prev', 'left', 'arrow', '‹' ),
17989 fc_button('next', 'right', 'arrow', '›' ),
17990 { tag: 'span', cls: 'fc-header-space' },
17991 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17999 cls : 'fc-header-center',
18003 cls: 'fc-header-title',
18006 html : 'month / year'
18014 cls : 'fc-header-right',
18016 /* fc_button('month', 'left', '', 'month' ),
18017 fc_button('week', '', '', 'week' ),
18018 fc_button('day', 'right', '', 'day' )
18030 header = this.header;
18033 var cal_heads = function() {
18035 // fixme - handle this.
18037 for (var i =0; i < Date.dayNames.length; i++) {
18038 var d = Date.dayNames[i];
18041 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
18042 html : d.substring(0,3)
18046 ret[0].cls += ' fc-first';
18047 ret[6].cls += ' fc-last';
18050 var cal_cell = function(n) {
18053 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
18058 cls: 'fc-day-number',
18062 cls: 'fc-day-content',
18066 style: 'position: relative;' // height: 17px;
18078 var cal_rows = function() {
18081 for (var r = 0; r < 6; r++) {
18088 for (var i =0; i < Date.dayNames.length; i++) {
18089 var d = Date.dayNames[i];
18090 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
18093 row.cn[0].cls+=' fc-first';
18094 row.cn[0].cn[0].style = 'min-height:90px';
18095 row.cn[6].cls+=' fc-last';
18099 ret[0].cls += ' fc-first';
18100 ret[4].cls += ' fc-prev-last';
18101 ret[5].cls += ' fc-last';
18108 cls: 'fc-border-separate',
18109 style : 'width:100%',
18117 cls : 'fc-first fc-last',
18135 cls : 'fc-content',
18136 style : "position: relative;",
18139 cls : 'fc-view fc-view-month fc-grid',
18140 style : 'position: relative',
18141 unselectable : 'on',
18144 cls : 'fc-event-container',
18145 style : 'position:absolute;z-index:8;top:0;left:0;'
18163 initEvents : function()
18166 throw "can not find store for calendar";
18172 style: "text-align:center",
18176 style: "background-color:white;width:50%;margin:250 auto",
18180 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
18191 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
18193 var size = this.el.select('.fc-content', true).first().getSize();
18194 this.maskEl.setSize(size.width, size.height);
18195 this.maskEl.enableDisplayMode("block");
18196 if(!this.loadMask){
18197 this.maskEl.hide();
18200 this.store = Roo.factory(this.store, Roo.data);
18201 this.store.on('load', this.onLoad, this);
18202 this.store.on('beforeload', this.onBeforeLoad, this);
18206 this.cells = this.el.select('.fc-day',true);
18207 //Roo.log(this.cells);
18208 this.textNodes = this.el.query('.fc-day-number');
18209 this.cells.addClassOnOver('fc-state-hover');
18211 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
18212 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
18213 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
18214 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
18216 this.on('monthchange', this.onMonthChange, this);
18218 this.update(new Date().clearTime());
18221 resize : function() {
18222 var sz = this.el.getSize();
18224 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
18225 this.el.select('.fc-day-content div',true).setHeight(34);
18230 showPrevMonth : function(e){
18231 this.update(this.activeDate.add("mo", -1));
18233 showToday : function(e){
18234 this.update(new Date().clearTime());
18237 showNextMonth : function(e){
18238 this.update(this.activeDate.add("mo", 1));
18242 showPrevYear : function(){
18243 this.update(this.activeDate.add("y", -1));
18247 showNextYear : function(){
18248 this.update(this.activeDate.add("y", 1));
18253 update : function(date)
18255 var vd = this.activeDate;
18256 this.activeDate = date;
18257 // if(vd && this.el){
18258 // var t = date.getTime();
18259 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
18260 // Roo.log('using add remove');
18262 // this.fireEvent('monthchange', this, date);
18264 // this.cells.removeClass("fc-state-highlight");
18265 // this.cells.each(function(c){
18266 // if(c.dateValue == t){
18267 // c.addClass("fc-state-highlight");
18268 // setTimeout(function(){
18269 // try{c.dom.firstChild.focus();}catch(e){}
18279 var days = date.getDaysInMonth();
18281 var firstOfMonth = date.getFirstDateOfMonth();
18282 var startingPos = firstOfMonth.getDay()-this.startDay;
18284 if(startingPos < this.startDay){
18288 var pm = date.add(Date.MONTH, -1);
18289 var prevStart = pm.getDaysInMonth()-startingPos;
18291 this.cells = this.el.select('.fc-day',true);
18292 this.textNodes = this.el.query('.fc-day-number');
18293 this.cells.addClassOnOver('fc-state-hover');
18295 var cells = this.cells.elements;
18296 var textEls = this.textNodes;
18298 Roo.each(cells, function(cell){
18299 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
18302 days += startingPos;
18304 // convert everything to numbers so it's fast
18305 var day = 86400000;
18306 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
18309 //Roo.log(prevStart);
18311 var today = new Date().clearTime().getTime();
18312 var sel = date.clearTime().getTime();
18313 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
18314 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
18315 var ddMatch = this.disabledDatesRE;
18316 var ddText = this.disabledDatesText;
18317 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
18318 var ddaysText = this.disabledDaysText;
18319 var format = this.format;
18321 var setCellClass = function(cal, cell){
18325 //Roo.log('set Cell Class');
18327 var t = d.getTime();
18331 cell.dateValue = t;
18333 cell.className += " fc-today";
18334 cell.className += " fc-state-highlight";
18335 cell.title = cal.todayText;
18338 // disable highlight in other month..
18339 //cell.className += " fc-state-highlight";
18344 cell.className = " fc-state-disabled";
18345 cell.title = cal.minText;
18349 cell.className = " fc-state-disabled";
18350 cell.title = cal.maxText;
18354 if(ddays.indexOf(d.getDay()) != -1){
18355 cell.title = ddaysText;
18356 cell.className = " fc-state-disabled";
18359 if(ddMatch && format){
18360 var fvalue = d.dateFormat(format);
18361 if(ddMatch.test(fvalue)){
18362 cell.title = ddText.replace("%0", fvalue);
18363 cell.className = " fc-state-disabled";
18367 if (!cell.initialClassName) {
18368 cell.initialClassName = cell.dom.className;
18371 cell.dom.className = cell.initialClassName + ' ' + cell.className;
18376 for(; i < startingPos; i++) {
18377 textEls[i].innerHTML = (++prevStart);
18378 d.setDate(d.getDate()+1);
18380 cells[i].className = "fc-past fc-other-month";
18381 setCellClass(this, cells[i]);
18386 for(; i < days; i++){
18387 intDay = i - startingPos + 1;
18388 textEls[i].innerHTML = (intDay);
18389 d.setDate(d.getDate()+1);
18391 cells[i].className = ''; // "x-date-active";
18392 setCellClass(this, cells[i]);
18396 for(; i < 42; i++) {
18397 textEls[i].innerHTML = (++extraDays);
18398 d.setDate(d.getDate()+1);
18400 cells[i].className = "fc-future fc-other-month";
18401 setCellClass(this, cells[i]);
18404 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
18406 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
18408 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
18409 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
18411 if(totalRows != 6){
18412 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
18413 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
18416 this.fireEvent('monthchange', this, date);
18420 if(!this.internalRender){
18421 var main = this.el.dom.firstChild;
18422 var w = main.offsetWidth;
18423 this.el.setWidth(w + this.el.getBorderWidth("lr"));
18424 Roo.fly(main).setWidth(w);
18425 this.internalRender = true;
18426 // opera does not respect the auto grow header center column
18427 // then, after it gets a width opera refuses to recalculate
18428 // without a second pass
18429 if(Roo.isOpera && !this.secondPass){
18430 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
18431 this.secondPass = true;
18432 this.update.defer(10, this, [date]);
18439 findCell : function(dt) {
18440 dt = dt.clearTime().getTime();
18442 this.cells.each(function(c){
18443 //Roo.log("check " +c.dateValue + '?=' + dt);
18444 if(c.dateValue == dt){
18454 findCells : function(ev) {
18455 var s = ev.start.clone().clearTime().getTime();
18457 var e= ev.end.clone().clearTime().getTime();
18460 this.cells.each(function(c){
18461 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
18463 if(c.dateValue > e){
18466 if(c.dateValue < s){
18475 // findBestRow: function(cells)
18479 // for (var i =0 ; i < cells.length;i++) {
18480 // ret = Math.max(cells[i].rows || 0,ret);
18487 addItem : function(ev)
18489 // look for vertical location slot in
18490 var cells = this.findCells(ev);
18492 // ev.row = this.findBestRow(cells);
18494 // work out the location.
18498 for(var i =0; i < cells.length; i++) {
18500 cells[i].row = cells[0].row;
18503 cells[i].row = cells[i].row + 1;
18513 if (crow.start.getY() == cells[i].getY()) {
18515 crow.end = cells[i];
18532 cells[0].events.push(ev);
18534 this.calevents.push(ev);
18537 clearEvents: function() {
18539 if(!this.calevents){
18543 Roo.each(this.cells.elements, function(c){
18549 Roo.each(this.calevents, function(e) {
18550 Roo.each(e.els, function(el) {
18551 el.un('mouseenter' ,this.onEventEnter, this);
18552 el.un('mouseleave' ,this.onEventLeave, this);
18557 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
18563 renderEvents: function()
18567 this.cells.each(function(c) {
18576 if(c.row != c.events.length){
18577 r = 4 - (4 - (c.row - c.events.length));
18580 c.events = ev.slice(0, r);
18581 c.more = ev.slice(r);
18583 if(c.more.length && c.more.length == 1){
18584 c.events.push(c.more.pop());
18587 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
18591 this.cells.each(function(c) {
18593 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
18596 for (var e = 0; e < c.events.length; e++){
18597 var ev = c.events[e];
18598 var rows = ev.rows;
18600 for(var i = 0; i < rows.length; i++) {
18602 // how many rows should it span..
18605 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
18606 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
18608 unselectable : "on",
18611 cls: 'fc-event-inner',
18615 // cls: 'fc-event-time',
18616 // html : cells.length > 1 ? '' : ev.time
18620 cls: 'fc-event-title',
18621 html : String.format('{0}', ev.title)
18628 cls: 'ui-resizable-handle ui-resizable-e',
18629 html : '  '
18636 cfg.cls += ' fc-event-start';
18638 if ((i+1) == rows.length) {
18639 cfg.cls += ' fc-event-end';
18642 var ctr = _this.el.select('.fc-event-container',true).first();
18643 var cg = ctr.createChild(cfg);
18645 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
18646 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
18648 var r = (c.more.length) ? 1 : 0;
18649 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
18650 cg.setWidth(ebox.right - sbox.x -2);
18652 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
18653 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
18654 cg.on('click', _this.onEventClick, _this, ev);
18665 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
18666 style : 'position: absolute',
18667 unselectable : "on",
18670 cls: 'fc-event-inner',
18674 cls: 'fc-event-title',
18682 cls: 'ui-resizable-handle ui-resizable-e',
18683 html : '  '
18689 var ctr = _this.el.select('.fc-event-container',true).first();
18690 var cg = ctr.createChild(cfg);
18692 var sbox = c.select('.fc-day-content',true).first().getBox();
18693 var ebox = c.select('.fc-day-content',true).first().getBox();
18695 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
18696 cg.setWidth(ebox.right - sbox.x -2);
18698 cg.on('click', _this.onMoreEventClick, _this, c.more);
18708 onEventEnter: function (e, el,event,d) {
18709 this.fireEvent('evententer', this, el, event);
18712 onEventLeave: function (e, el,event,d) {
18713 this.fireEvent('eventleave', this, el, event);
18716 onEventClick: function (e, el,event,d) {
18717 this.fireEvent('eventclick', this, el, event);
18720 onMonthChange: function () {
18724 onMoreEventClick: function(e, el, more)
18728 this.calpopover.placement = 'right';
18729 this.calpopover.setTitle('More');
18731 this.calpopover.setContent('');
18733 var ctr = this.calpopover.el.select('.popover-content', true).first();
18735 Roo.each(more, function(m){
18737 cls : 'fc-event-hori fc-event-draggable',
18740 var cg = ctr.createChild(cfg);
18742 cg.on('click', _this.onEventClick, _this, m);
18745 this.calpopover.show(el);
18750 onLoad: function ()
18752 this.calevents = [];
18755 if(this.store.getCount() > 0){
18756 this.store.data.each(function(d){
18759 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
18760 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
18761 time : d.data.start_time,
18762 title : d.data.title,
18763 description : d.data.description,
18764 venue : d.data.venue
18769 this.renderEvents();
18771 if(this.calevents.length && this.loadMask){
18772 this.maskEl.hide();
18776 onBeforeLoad: function()
18778 this.clearEvents();
18780 this.maskEl.show();
18794 * @class Roo.bootstrap.Popover
18795 * @extends Roo.bootstrap.Component
18796 * Bootstrap Popover class
18797 * @cfg {String} html contents of the popover (or false to use children..)
18798 * @cfg {String} title of popover (or false to hide)
18799 * @cfg {String} placement how it is placed
18800 * @cfg {String} trigger click || hover (or false to trigger manually)
18801 * @cfg {String} over what (parent or false to trigger manually.)
18802 * @cfg {Number} delay - delay before showing
18805 * Create a new Popover
18806 * @param {Object} config The config object
18809 Roo.bootstrap.Popover = function(config){
18810 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
18816 * After the popover show
18818 * @param {Roo.bootstrap.Popover} this
18823 * After the popover hide
18825 * @param {Roo.bootstrap.Popover} this
18831 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
18833 title: 'Fill in a title',
18836 placement : 'right',
18837 trigger : 'hover', // hover
18843 can_build_overlaid : false,
18845 getChildContainer : function()
18847 return this.el.select('.popover-content',true).first();
18850 getAutoCreate : function(){
18853 cls : 'popover roo-dynamic',
18854 style: 'display:block',
18860 cls : 'popover-inner',
18864 cls: 'popover-title popover-header',
18868 cls : 'popover-content popover-body',
18879 setTitle: function(str)
18882 this.el.select('.popover-title',true).first().dom.innerHTML = str;
18884 setContent: function(str)
18887 this.el.select('.popover-content',true).first().dom.innerHTML = str;
18889 // as it get's added to the bottom of the page.
18890 onRender : function(ct, position)
18892 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18894 var cfg = Roo.apply({}, this.getAutoCreate());
18898 cfg.cls += ' ' + this.cls;
18901 cfg.style = this.style;
18903 //Roo.log("adding to ");
18904 this.el = Roo.get(document.body).createChild(cfg, position);
18905 // Roo.log(this.el);
18910 initEvents : function()
18912 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
18913 this.el.enableDisplayMode('block');
18915 if (this.over === false) {
18918 if (this.triggers === false) {
18921 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18922 var triggers = this.trigger ? this.trigger.split(' ') : [];
18923 Roo.each(triggers, function(trigger) {
18925 if (trigger == 'click') {
18926 on_el.on('click', this.toggle, this);
18927 } else if (trigger != 'manual') {
18928 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
18929 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
18931 on_el.on(eventIn ,this.enter, this);
18932 on_el.on(eventOut, this.leave, this);
18943 toggle : function () {
18944 this.hoverState == 'in' ? this.leave() : this.enter();
18947 enter : function () {
18949 clearTimeout(this.timeout);
18951 this.hoverState = 'in';
18953 if (!this.delay || !this.delay.show) {
18958 this.timeout = setTimeout(function () {
18959 if (_t.hoverState == 'in') {
18962 }, this.delay.show)
18965 leave : function() {
18966 clearTimeout(this.timeout);
18968 this.hoverState = 'out';
18970 if (!this.delay || !this.delay.hide) {
18975 this.timeout = setTimeout(function () {
18976 if (_t.hoverState == 'out') {
18979 }, this.delay.hide)
18982 show : function (on_el)
18985 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18989 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18990 if (this.html !== false) {
18991 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18993 this.el.removeClass([
18994 'fade','top','bottom', 'left', 'right','in',
18995 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18997 if (!this.title.length) {
18998 this.el.select('.popover-title',true).hide();
19001 var placement = typeof this.placement == 'function' ?
19002 this.placement.call(this, this.el, on_el) :
19005 var autoToken = /\s?auto?\s?/i;
19006 var autoPlace = autoToken.test(placement);
19008 placement = placement.replace(autoToken, '') || 'top';
19012 //this.el.setXY([0,0]);
19014 this.el.dom.style.display='block';
19015 this.el.addClass(placement);
19017 //this.el.appendTo(on_el);
19019 var p = this.getPosition();
19020 var box = this.el.getBox();
19025 var align = Roo.bootstrap.Popover.alignment[placement];
19028 this.el.alignTo(on_el, align[0],align[1]);
19029 //var arrow = this.el.select('.arrow',true).first();
19030 //arrow.set(align[2],
19032 this.el.addClass('in');
19035 if (this.el.hasClass('fade')) {
19039 this.hoverState = 'in';
19041 this.fireEvent('show', this);
19046 this.el.setXY([0,0]);
19047 this.el.removeClass('in');
19049 this.hoverState = null;
19051 this.fireEvent('hide', this);
19056 Roo.bootstrap.Popover.alignment = {
19057 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
19058 'right' : ['l-r', [10,0], 'left bs-popover-left'],
19059 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
19060 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
19071 * @class Roo.bootstrap.Progress
19072 * @extends Roo.bootstrap.Component
19073 * Bootstrap Progress class
19074 * @cfg {Boolean} striped striped of the progress bar
19075 * @cfg {Boolean} active animated of the progress bar
19079 * Create a new Progress
19080 * @param {Object} config The config object
19083 Roo.bootstrap.Progress = function(config){
19084 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
19087 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
19092 getAutoCreate : function(){
19100 cfg.cls += ' progress-striped';
19104 cfg.cls += ' active';
19123 * @class Roo.bootstrap.ProgressBar
19124 * @extends Roo.bootstrap.Component
19125 * Bootstrap ProgressBar class
19126 * @cfg {Number} aria_valuenow aria-value now
19127 * @cfg {Number} aria_valuemin aria-value min
19128 * @cfg {Number} aria_valuemax aria-value max
19129 * @cfg {String} label label for the progress bar
19130 * @cfg {String} panel (success | info | warning | danger )
19131 * @cfg {String} role role of the progress bar
19132 * @cfg {String} sr_only text
19136 * Create a new ProgressBar
19137 * @param {Object} config The config object
19140 Roo.bootstrap.ProgressBar = function(config){
19141 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
19144 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
19148 aria_valuemax : 100,
19154 getAutoCreate : function()
19159 cls: 'progress-bar',
19160 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
19172 cfg.role = this.role;
19175 if(this.aria_valuenow){
19176 cfg['aria-valuenow'] = this.aria_valuenow;
19179 if(this.aria_valuemin){
19180 cfg['aria-valuemin'] = this.aria_valuemin;
19183 if(this.aria_valuemax){
19184 cfg['aria-valuemax'] = this.aria_valuemax;
19187 if(this.label && !this.sr_only){
19188 cfg.html = this.label;
19192 cfg.cls += ' progress-bar-' + this.panel;
19198 update : function(aria_valuenow)
19200 this.aria_valuenow = aria_valuenow;
19202 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
19217 * @class Roo.bootstrap.TabGroup
19218 * @extends Roo.bootstrap.Column
19219 * Bootstrap Column class
19220 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
19221 * @cfg {Boolean} carousel true to make the group behave like a carousel
19222 * @cfg {Boolean} bullets show bullets for the panels
19223 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
19224 * @cfg {Number} timer auto slide timer .. default 0 millisecond
19225 * @cfg {Boolean} showarrow (true|false) show arrow default true
19228 * Create a new TabGroup
19229 * @param {Object} config The config object
19232 Roo.bootstrap.TabGroup = function(config){
19233 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
19235 this.navId = Roo.id();
19238 Roo.bootstrap.TabGroup.register(this);
19242 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
19245 transition : false,
19250 slideOnTouch : false,
19253 getAutoCreate : function()
19255 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
19257 cfg.cls += ' tab-content';
19259 if (this.carousel) {
19260 cfg.cls += ' carousel slide';
19263 cls : 'carousel-inner',
19267 if(this.bullets && !Roo.isTouch){
19270 cls : 'carousel-bullets',
19274 if(this.bullets_cls){
19275 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
19282 cfg.cn[0].cn.push(bullets);
19285 if(this.showarrow){
19286 cfg.cn[0].cn.push({
19288 class : 'carousel-arrow',
19292 class : 'carousel-prev',
19296 class : 'fa fa-chevron-left'
19302 class : 'carousel-next',
19306 class : 'fa fa-chevron-right'
19319 initEvents: function()
19321 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
19322 // this.el.on("touchstart", this.onTouchStart, this);
19325 if(this.autoslide){
19328 this.slideFn = window.setInterval(function() {
19329 _this.showPanelNext();
19333 if(this.showarrow){
19334 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
19335 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
19341 // onTouchStart : function(e, el, o)
19343 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
19347 // this.showPanelNext();
19351 getChildContainer : function()
19353 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
19357 * register a Navigation item
19358 * @param {Roo.bootstrap.NavItem} the navitem to add
19360 register : function(item)
19362 this.tabs.push( item);
19363 item.navId = this.navId; // not really needed..
19368 getActivePanel : function()
19371 Roo.each(this.tabs, function(t) {
19381 getPanelByName : function(n)
19384 Roo.each(this.tabs, function(t) {
19385 if (t.tabId == n) {
19393 indexOfPanel : function(p)
19396 Roo.each(this.tabs, function(t,i) {
19397 if (t.tabId == p.tabId) {
19406 * show a specific panel
19407 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
19408 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
19410 showPanel : function (pan)
19412 if(this.transition || typeof(pan) == 'undefined'){
19413 Roo.log("waiting for the transitionend");
19417 if (typeof(pan) == 'number') {
19418 pan = this.tabs[pan];
19421 if (typeof(pan) == 'string') {
19422 pan = this.getPanelByName(pan);
19425 var cur = this.getActivePanel();
19428 Roo.log('pan or acitve pan is undefined');
19432 if (pan.tabId == this.getActivePanel().tabId) {
19436 if (false === cur.fireEvent('beforedeactivate')) {
19440 if(this.bullets > 0 && !Roo.isTouch){
19441 this.setActiveBullet(this.indexOfPanel(pan));
19444 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
19446 //class="carousel-item carousel-item-next carousel-item-left"
19448 this.transition = true;
19449 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
19450 var lr = dir == 'next' ? 'left' : 'right';
19451 pan.el.addClass(dir); // or prev
19452 pan.el.addClass('carousel-item-' + dir); // or prev
19453 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
19454 cur.el.addClass(lr); // or right
19455 pan.el.addClass(lr);
19456 cur.el.addClass('carousel-item-' +lr); // or right
19457 pan.el.addClass('carousel-item-' +lr);
19461 cur.el.on('transitionend', function() {
19462 Roo.log("trans end?");
19464 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
19465 pan.setActive(true);
19467 cur.el.removeClass([lr, 'carousel-item-' + lr]);
19468 cur.setActive(false);
19470 _this.transition = false;
19472 }, this, { single: true } );
19477 cur.setActive(false);
19478 pan.setActive(true);
19483 showPanelNext : function()
19485 var i = this.indexOfPanel(this.getActivePanel());
19487 if (i >= this.tabs.length - 1 && !this.autoslide) {
19491 if (i >= this.tabs.length - 1 && this.autoslide) {
19495 this.showPanel(this.tabs[i+1]);
19498 showPanelPrev : function()
19500 var i = this.indexOfPanel(this.getActivePanel());
19502 if (i < 1 && !this.autoslide) {
19506 if (i < 1 && this.autoslide) {
19507 i = this.tabs.length;
19510 this.showPanel(this.tabs[i-1]);
19514 addBullet: function()
19516 if(!this.bullets || Roo.isTouch){
19519 var ctr = this.el.select('.carousel-bullets',true).first();
19520 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
19521 var bullet = ctr.createChild({
19522 cls : 'bullet bullet-' + i
19523 },ctr.dom.lastChild);
19528 bullet.on('click', (function(e, el, o, ii, t){
19530 e.preventDefault();
19532 this.showPanel(ii);
19534 if(this.autoslide && this.slideFn){
19535 clearInterval(this.slideFn);
19536 this.slideFn = window.setInterval(function() {
19537 _this.showPanelNext();
19541 }).createDelegate(this, [i, bullet], true));
19546 setActiveBullet : function(i)
19552 Roo.each(this.el.select('.bullet', true).elements, function(el){
19553 el.removeClass('selected');
19556 var bullet = this.el.select('.bullet-' + i, true).first();
19562 bullet.addClass('selected');
19573 Roo.apply(Roo.bootstrap.TabGroup, {
19577 * register a Navigation Group
19578 * @param {Roo.bootstrap.NavGroup} the navgroup to add
19580 register : function(navgrp)
19582 this.groups[navgrp.navId] = navgrp;
19586 * fetch a Navigation Group based on the navigation ID
19587 * if one does not exist , it will get created.
19588 * @param {string} the navgroup to add
19589 * @returns {Roo.bootstrap.NavGroup} the navgroup
19591 get: function(navId) {
19592 if (typeof(this.groups[navId]) == 'undefined') {
19593 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
19595 return this.groups[navId] ;
19610 * @class Roo.bootstrap.TabPanel
19611 * @extends Roo.bootstrap.Component
19612 * Bootstrap TabPanel class
19613 * @cfg {Boolean} active panel active
19614 * @cfg {String} html panel content
19615 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
19616 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
19617 * @cfg {String} href click to link..
19621 * Create a new TabPanel
19622 * @param {Object} config The config object
19625 Roo.bootstrap.TabPanel = function(config){
19626 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
19630 * Fires when the active status changes
19631 * @param {Roo.bootstrap.TabPanel} this
19632 * @param {Boolean} state the new state
19637 * @event beforedeactivate
19638 * Fires before a tab is de-activated - can be used to do validation on a form.
19639 * @param {Roo.bootstrap.TabPanel} this
19640 * @return {Boolean} false if there is an error
19643 'beforedeactivate': true
19646 this.tabId = this.tabId || Roo.id();
19650 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
19658 getAutoCreate : function(){
19663 // item is needed for carousel - not sure if it has any effect otherwise
19664 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
19665 html: this.html || ''
19669 cfg.cls += ' active';
19673 cfg.tabId = this.tabId;
19681 initEvents: function()
19683 var p = this.parent();
19685 this.navId = this.navId || p.navId;
19687 if (typeof(this.navId) != 'undefined') {
19688 // not really needed.. but just in case.. parent should be a NavGroup.
19689 var tg = Roo.bootstrap.TabGroup.get(this.navId);
19693 var i = tg.tabs.length - 1;
19695 if(this.active && tg.bullets > 0 && i < tg.bullets){
19696 tg.setActiveBullet(i);
19700 this.el.on('click', this.onClick, this);
19703 this.el.on("touchstart", this.onTouchStart, this);
19704 this.el.on("touchmove", this.onTouchMove, this);
19705 this.el.on("touchend", this.onTouchEnd, this);
19710 onRender : function(ct, position)
19712 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
19715 setActive : function(state)
19717 Roo.log("panel - set active " + this.tabId + "=" + state);
19719 this.active = state;
19721 this.el.removeClass('active');
19723 } else if (!this.el.hasClass('active')) {
19724 this.el.addClass('active');
19727 this.fireEvent('changed', this, state);
19730 onClick : function(e)
19732 e.preventDefault();
19734 if(!this.href.length){
19738 window.location.href = this.href;
19747 onTouchStart : function(e)
19749 this.swiping = false;
19751 this.startX = e.browserEvent.touches[0].clientX;
19752 this.startY = e.browserEvent.touches[0].clientY;
19755 onTouchMove : function(e)
19757 this.swiping = true;
19759 this.endX = e.browserEvent.touches[0].clientX;
19760 this.endY = e.browserEvent.touches[0].clientY;
19763 onTouchEnd : function(e)
19770 var tabGroup = this.parent();
19772 if(this.endX > this.startX){ // swiping right
19773 tabGroup.showPanelPrev();
19777 if(this.startX > this.endX){ // swiping left
19778 tabGroup.showPanelNext();
19797 * @class Roo.bootstrap.DateField
19798 * @extends Roo.bootstrap.Input
19799 * Bootstrap DateField class
19800 * @cfg {Number} weekStart default 0
19801 * @cfg {String} viewMode default empty, (months|years)
19802 * @cfg {String} minViewMode default empty, (months|years)
19803 * @cfg {Number} startDate default -Infinity
19804 * @cfg {Number} endDate default Infinity
19805 * @cfg {Boolean} todayHighlight default false
19806 * @cfg {Boolean} todayBtn default false
19807 * @cfg {Boolean} calendarWeeks default false
19808 * @cfg {Object} daysOfWeekDisabled default empty
19809 * @cfg {Boolean} singleMode default false (true | false)
19811 * @cfg {Boolean} keyboardNavigation default true
19812 * @cfg {String} language default en
19815 * Create a new DateField
19816 * @param {Object} config The config object
19819 Roo.bootstrap.DateField = function(config){
19820 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
19824 * Fires when this field show.
19825 * @param {Roo.bootstrap.DateField} this
19826 * @param {Mixed} date The date value
19831 * Fires when this field hide.
19832 * @param {Roo.bootstrap.DateField} this
19833 * @param {Mixed} date The date value
19838 * Fires when select a date.
19839 * @param {Roo.bootstrap.DateField} this
19840 * @param {Mixed} date The date value
19844 * @event beforeselect
19845 * Fires when before select a date.
19846 * @param {Roo.bootstrap.DateField} this
19847 * @param {Mixed} date The date value
19849 beforeselect : true
19853 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
19856 * @cfg {String} format
19857 * The default date format string which can be overriden for localization support. The format must be
19858 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
19862 * @cfg {String} altFormats
19863 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
19864 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
19866 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
19874 todayHighlight : false,
19880 keyboardNavigation: true,
19882 calendarWeeks: false,
19884 startDate: -Infinity,
19888 daysOfWeekDisabled: [],
19892 singleMode : false,
19894 UTCDate: function()
19896 return new Date(Date.UTC.apply(Date, arguments));
19899 UTCToday: function()
19901 var today = new Date();
19902 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
19905 getDate: function() {
19906 var d = this.getUTCDate();
19907 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
19910 getUTCDate: function() {
19914 setDate: function(d) {
19915 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
19918 setUTCDate: function(d) {
19920 this.setValue(this.formatDate(this.date));
19923 onRender: function(ct, position)
19926 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
19928 this.language = this.language || 'en';
19929 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
19930 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
19932 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
19933 this.format = this.format || 'm/d/y';
19934 this.isInline = false;
19935 this.isInput = true;
19936 this.component = this.el.select('.add-on', true).first() || false;
19937 this.component = (this.component && this.component.length === 0) ? false : this.component;
19938 this.hasInput = this.component && this.inputEl().length;
19940 if (typeof(this.minViewMode === 'string')) {
19941 switch (this.minViewMode) {
19943 this.minViewMode = 1;
19946 this.minViewMode = 2;
19949 this.minViewMode = 0;
19954 if (typeof(this.viewMode === 'string')) {
19955 switch (this.viewMode) {
19968 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
19970 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
19972 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19974 this.picker().on('mousedown', this.onMousedown, this);
19975 this.picker().on('click', this.onClick, this);
19977 this.picker().addClass('datepicker-dropdown');
19979 this.startViewMode = this.viewMode;
19981 if(this.singleMode){
19982 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19983 v.setVisibilityMode(Roo.Element.DISPLAY);
19987 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19988 v.setStyle('width', '189px');
19992 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19993 if(!this.calendarWeeks){
19998 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19999 v.attr('colspan', function(i, val){
20000 return parseInt(val) + 1;
20005 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
20007 this.setStartDate(this.startDate);
20008 this.setEndDate(this.endDate);
20010 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
20017 if(this.isInline) {
20022 picker : function()
20024 return this.pickerEl;
20025 // return this.el.select('.datepicker', true).first();
20028 fillDow: function()
20030 var dowCnt = this.weekStart;
20039 if(this.calendarWeeks){
20047 while (dowCnt < this.weekStart + 7) {
20051 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
20055 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
20058 fillMonths: function()
20061 var months = this.picker().select('>.datepicker-months td', true).first();
20063 months.dom.innerHTML = '';
20069 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
20072 months.createChild(month);
20079 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;
20081 if (this.date < this.startDate) {
20082 this.viewDate = new Date(this.startDate);
20083 } else if (this.date > this.endDate) {
20084 this.viewDate = new Date(this.endDate);
20086 this.viewDate = new Date(this.date);
20094 var d = new Date(this.viewDate),
20095 year = d.getUTCFullYear(),
20096 month = d.getUTCMonth(),
20097 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
20098 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
20099 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
20100 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
20101 currentDate = this.date && this.date.valueOf(),
20102 today = this.UTCToday();
20104 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
20106 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20108 // this.picker.select('>tfoot th.today').
20109 // .text(dates[this.language].today)
20110 // .toggle(this.todayBtn !== false);
20112 this.updateNavArrows();
20115 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
20117 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
20119 prevMonth.setUTCDate(day);
20121 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
20123 var nextMonth = new Date(prevMonth);
20125 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
20127 nextMonth = nextMonth.valueOf();
20129 var fillMonths = false;
20131 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
20133 while(prevMonth.valueOf() <= nextMonth) {
20136 if (prevMonth.getUTCDay() === this.weekStart) {
20138 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
20146 if(this.calendarWeeks){
20147 // ISO 8601: First week contains first thursday.
20148 // ISO also states week starts on Monday, but we can be more abstract here.
20150 // Start of current week: based on weekstart/current date
20151 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
20152 // Thursday of this week
20153 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
20154 // First Thursday of year, year from thursday
20155 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
20156 // Calendar week: ms between thursdays, div ms per day, div 7 days
20157 calWeek = (th - yth) / 864e5 / 7 + 1;
20159 fillMonths.cn.push({
20167 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
20169 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
20172 if (this.todayHighlight &&
20173 prevMonth.getUTCFullYear() == today.getFullYear() &&
20174 prevMonth.getUTCMonth() == today.getMonth() &&
20175 prevMonth.getUTCDate() == today.getDate()) {
20176 clsName += ' today';
20179 if (currentDate && prevMonth.valueOf() === currentDate) {
20180 clsName += ' active';
20183 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
20184 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
20185 clsName += ' disabled';
20188 fillMonths.cn.push({
20190 cls: 'day ' + clsName,
20191 html: prevMonth.getDate()
20194 prevMonth.setDate(prevMonth.getDate()+1);
20197 var currentYear = this.date && this.date.getUTCFullYear();
20198 var currentMonth = this.date && this.date.getUTCMonth();
20200 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
20202 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
20203 v.removeClass('active');
20205 if(currentYear === year && k === currentMonth){
20206 v.addClass('active');
20209 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
20210 v.addClass('disabled');
20216 year = parseInt(year/10, 10) * 10;
20218 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
20220 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
20223 for (var i = -1; i < 11; i++) {
20224 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
20226 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
20234 showMode: function(dir)
20237 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
20240 Roo.each(this.picker().select('>div',true).elements, function(v){
20241 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20244 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
20249 if(this.isInline) {
20253 this.picker().removeClass(['bottom', 'top']);
20255 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20257 * place to the top of element!
20261 this.picker().addClass('top');
20262 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20267 this.picker().addClass('bottom');
20269 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20272 parseDate : function(value)
20274 if(!value || value instanceof Date){
20277 var v = Date.parseDate(value, this.format);
20278 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
20279 v = Date.parseDate(value, 'Y-m-d');
20281 if(!v && this.altFormats){
20282 if(!this.altFormatsArray){
20283 this.altFormatsArray = this.altFormats.split("|");
20285 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
20286 v = Date.parseDate(value, this.altFormatsArray[i]);
20292 formatDate : function(date, fmt)
20294 return (!date || !(date instanceof Date)) ?
20295 date : date.dateFormat(fmt || this.format);
20298 onFocus : function()
20300 Roo.bootstrap.DateField.superclass.onFocus.call(this);
20304 onBlur : function()
20306 Roo.bootstrap.DateField.superclass.onBlur.call(this);
20308 var d = this.inputEl().getValue();
20315 showPopup : function()
20317 this.picker().show();
20321 this.fireEvent('showpopup', this, this.date);
20324 hidePopup : function()
20326 if(this.isInline) {
20329 this.picker().hide();
20330 this.viewMode = this.startViewMode;
20333 this.fireEvent('hidepopup', this, this.date);
20337 onMousedown: function(e)
20339 e.stopPropagation();
20340 e.preventDefault();
20345 Roo.bootstrap.DateField.superclass.keyup.call(this);
20349 setValue: function(v)
20351 if(this.fireEvent('beforeselect', this, v) !== false){
20352 var d = new Date(this.parseDate(v) ).clearTime();
20354 if(isNaN(d.getTime())){
20355 this.date = this.viewDate = '';
20356 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
20360 v = this.formatDate(d);
20362 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
20364 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
20368 this.fireEvent('select', this, this.date);
20372 getValue: function()
20374 return this.formatDate(this.date);
20377 fireKey: function(e)
20379 if (!this.picker().isVisible()){
20380 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20386 var dateChanged = false,
20388 newDate, newViewDate;
20393 e.preventDefault();
20397 if (!this.keyboardNavigation) {
20400 dir = e.keyCode == 37 ? -1 : 1;
20403 newDate = this.moveYear(this.date, dir);
20404 newViewDate = this.moveYear(this.viewDate, dir);
20405 } else if (e.shiftKey){
20406 newDate = this.moveMonth(this.date, dir);
20407 newViewDate = this.moveMonth(this.viewDate, dir);
20409 newDate = new Date(this.date);
20410 newDate.setUTCDate(this.date.getUTCDate() + dir);
20411 newViewDate = new Date(this.viewDate);
20412 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
20414 if (this.dateWithinRange(newDate)){
20415 this.date = newDate;
20416 this.viewDate = newViewDate;
20417 this.setValue(this.formatDate(this.date));
20419 e.preventDefault();
20420 dateChanged = true;
20425 if (!this.keyboardNavigation) {
20428 dir = e.keyCode == 38 ? -1 : 1;
20430 newDate = this.moveYear(this.date, dir);
20431 newViewDate = this.moveYear(this.viewDate, dir);
20432 } else if (e.shiftKey){
20433 newDate = this.moveMonth(this.date, dir);
20434 newViewDate = this.moveMonth(this.viewDate, dir);
20436 newDate = new Date(this.date);
20437 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
20438 newViewDate = new Date(this.viewDate);
20439 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
20441 if (this.dateWithinRange(newDate)){
20442 this.date = newDate;
20443 this.viewDate = newViewDate;
20444 this.setValue(this.formatDate(this.date));
20446 e.preventDefault();
20447 dateChanged = true;
20451 this.setValue(this.formatDate(this.date));
20453 e.preventDefault();
20456 this.setValue(this.formatDate(this.date));
20470 onClick: function(e)
20472 e.stopPropagation();
20473 e.preventDefault();
20475 var target = e.getTarget();
20477 if(target.nodeName.toLowerCase() === 'i'){
20478 target = Roo.get(target).dom.parentNode;
20481 var nodeName = target.nodeName;
20482 var className = target.className;
20483 var html = target.innerHTML;
20484 //Roo.log(nodeName);
20486 switch(nodeName.toLowerCase()) {
20488 switch(className) {
20494 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
20495 switch(this.viewMode){
20497 this.viewDate = this.moveMonth(this.viewDate, dir);
20501 this.viewDate = this.moveYear(this.viewDate, dir);
20507 var date = new Date();
20508 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
20510 this.setValue(this.formatDate(this.date));
20517 if (className.indexOf('disabled') < 0) {
20518 this.viewDate.setUTCDate(1);
20519 if (className.indexOf('month') > -1) {
20520 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
20522 var year = parseInt(html, 10) || 0;
20523 this.viewDate.setUTCFullYear(year);
20527 if(this.singleMode){
20528 this.setValue(this.formatDate(this.viewDate));
20539 //Roo.log(className);
20540 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
20541 var day = parseInt(html, 10) || 1;
20542 var year = this.viewDate.getUTCFullYear(),
20543 month = this.viewDate.getUTCMonth();
20545 if (className.indexOf('old') > -1) {
20552 } else if (className.indexOf('new') > -1) {
20560 //Roo.log([year,month,day]);
20561 this.date = this.UTCDate(year, month, day,0,0,0,0);
20562 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
20564 //Roo.log(this.formatDate(this.date));
20565 this.setValue(this.formatDate(this.date));
20572 setStartDate: function(startDate)
20574 this.startDate = startDate || -Infinity;
20575 if (this.startDate !== -Infinity) {
20576 this.startDate = this.parseDate(this.startDate);
20579 this.updateNavArrows();
20582 setEndDate: function(endDate)
20584 this.endDate = endDate || Infinity;
20585 if (this.endDate !== Infinity) {
20586 this.endDate = this.parseDate(this.endDate);
20589 this.updateNavArrows();
20592 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
20594 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
20595 if (typeof(this.daysOfWeekDisabled) !== 'object') {
20596 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
20598 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
20599 return parseInt(d, 10);
20602 this.updateNavArrows();
20605 updateNavArrows: function()
20607 if(this.singleMode){
20611 var d = new Date(this.viewDate),
20612 year = d.getUTCFullYear(),
20613 month = d.getUTCMonth();
20615 Roo.each(this.picker().select('.prev', true).elements, function(v){
20617 switch (this.viewMode) {
20620 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
20626 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
20633 Roo.each(this.picker().select('.next', true).elements, function(v){
20635 switch (this.viewMode) {
20638 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
20644 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
20652 moveMonth: function(date, dir)
20657 var new_date = new Date(date.valueOf()),
20658 day = new_date.getUTCDate(),
20659 month = new_date.getUTCMonth(),
20660 mag = Math.abs(dir),
20662 dir = dir > 0 ? 1 : -1;
20665 // If going back one month, make sure month is not current month
20666 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
20668 return new_date.getUTCMonth() == month;
20670 // If going forward one month, make sure month is as expected
20671 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
20673 return new_date.getUTCMonth() != new_month;
20675 new_month = month + dir;
20676 new_date.setUTCMonth(new_month);
20677 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
20678 if (new_month < 0 || new_month > 11) {
20679 new_month = (new_month + 12) % 12;
20682 // For magnitudes >1, move one month at a time...
20683 for (var i=0; i<mag; i++) {
20684 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
20685 new_date = this.moveMonth(new_date, dir);
20687 // ...then reset the day, keeping it in the new month
20688 new_month = new_date.getUTCMonth();
20689 new_date.setUTCDate(day);
20691 return new_month != new_date.getUTCMonth();
20694 // Common date-resetting loop -- if date is beyond end of month, make it
20697 new_date.setUTCDate(--day);
20698 new_date.setUTCMonth(new_month);
20703 moveYear: function(date, dir)
20705 return this.moveMonth(date, dir*12);
20708 dateWithinRange: function(date)
20710 return date >= this.startDate && date <= this.endDate;
20716 this.picker().remove();
20719 validateValue : function(value)
20721 if(this.getVisibilityEl().hasClass('hidden')){
20725 if(value.length < 1) {
20726 if(this.allowBlank){
20732 if(value.length < this.minLength){
20735 if(value.length > this.maxLength){
20739 var vt = Roo.form.VTypes;
20740 if(!vt[this.vtype](value, this)){
20744 if(typeof this.validator == "function"){
20745 var msg = this.validator(value);
20751 if(this.regex && !this.regex.test(value)){
20755 if(typeof(this.parseDate(value)) == 'undefined'){
20759 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
20763 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
20773 this.date = this.viewDate = '';
20775 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
20780 Roo.apply(Roo.bootstrap.DateField, {
20791 html: '<i class="fa fa-arrow-left"/>'
20801 html: '<i class="fa fa-arrow-right"/>'
20843 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
20844 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
20845 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
20846 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20847 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
20860 navFnc: 'FullYear',
20865 navFnc: 'FullYear',
20870 Roo.apply(Roo.bootstrap.DateField, {
20874 cls: 'datepicker dropdown-menu roo-dynamic',
20878 cls: 'datepicker-days',
20882 cls: 'table-condensed',
20884 Roo.bootstrap.DateField.head,
20888 Roo.bootstrap.DateField.footer
20895 cls: 'datepicker-months',
20899 cls: 'table-condensed',
20901 Roo.bootstrap.DateField.head,
20902 Roo.bootstrap.DateField.content,
20903 Roo.bootstrap.DateField.footer
20910 cls: 'datepicker-years',
20914 cls: 'table-condensed',
20916 Roo.bootstrap.DateField.head,
20917 Roo.bootstrap.DateField.content,
20918 Roo.bootstrap.DateField.footer
20937 * @class Roo.bootstrap.TimeField
20938 * @extends Roo.bootstrap.Input
20939 * Bootstrap DateField class
20943 * Create a new TimeField
20944 * @param {Object} config The config object
20947 Roo.bootstrap.TimeField = function(config){
20948 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
20952 * Fires when this field show.
20953 * @param {Roo.bootstrap.DateField} thisthis
20954 * @param {Mixed} date The date value
20959 * Fires when this field hide.
20960 * @param {Roo.bootstrap.DateField} this
20961 * @param {Mixed} date The date value
20966 * Fires when select a date.
20967 * @param {Roo.bootstrap.DateField} this
20968 * @param {Mixed} date The date value
20974 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20977 * @cfg {String} format
20978 * The default time format string which can be overriden for localization support. The format must be
20979 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20983 onRender: function(ct, position)
20986 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20988 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20990 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20992 this.pop = this.picker().select('>.datepicker-time',true).first();
20993 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20995 this.picker().on('mousedown', this.onMousedown, this);
20996 this.picker().on('click', this.onClick, this);
20998 this.picker().addClass('datepicker-dropdown');
21003 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
21004 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
21005 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
21006 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
21007 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
21008 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
21012 fireKey: function(e){
21013 if (!this.picker().isVisible()){
21014 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21020 e.preventDefault();
21028 this.onTogglePeriod();
21031 this.onIncrementMinutes();
21034 this.onDecrementMinutes();
21043 onClick: function(e) {
21044 e.stopPropagation();
21045 e.preventDefault();
21048 picker : function()
21050 return this.el.select('.datepicker', true).first();
21053 fillTime: function()
21055 var time = this.pop.select('tbody', true).first();
21057 time.dom.innerHTML = '';
21072 cls: 'hours-up glyphicon glyphicon-chevron-up'
21092 cls: 'minutes-up glyphicon glyphicon-chevron-up'
21113 cls: 'timepicker-hour',
21128 cls: 'timepicker-minute',
21143 cls: 'btn btn-primary period',
21165 cls: 'hours-down glyphicon glyphicon-chevron-down'
21185 cls: 'minutes-down glyphicon glyphicon-chevron-down'
21203 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
21210 var hours = this.time.getHours();
21211 var minutes = this.time.getMinutes();
21224 hours = hours - 12;
21228 hours = '0' + hours;
21232 minutes = '0' + minutes;
21235 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
21236 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
21237 this.pop.select('button', true).first().dom.innerHTML = period;
21243 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
21245 var cls = ['bottom'];
21247 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
21254 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
21259 this.picker().addClass(cls.join('-'));
21263 Roo.each(cls, function(c){
21265 _this.picker().setTop(_this.inputEl().getHeight());
21269 _this.picker().setTop(0 - _this.picker().getHeight());
21274 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
21278 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
21285 onFocus : function()
21287 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
21291 onBlur : function()
21293 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
21299 this.picker().show();
21304 this.fireEvent('show', this, this.date);
21309 this.picker().hide();
21312 this.fireEvent('hide', this, this.date);
21315 setTime : function()
21318 this.setValue(this.time.format(this.format));
21320 this.fireEvent('select', this, this.date);
21325 onMousedown: function(e){
21326 e.stopPropagation();
21327 e.preventDefault();
21330 onIncrementHours: function()
21332 Roo.log('onIncrementHours');
21333 this.time = this.time.add(Date.HOUR, 1);
21338 onDecrementHours: function()
21340 Roo.log('onDecrementHours');
21341 this.time = this.time.add(Date.HOUR, -1);
21345 onIncrementMinutes: function()
21347 Roo.log('onIncrementMinutes');
21348 this.time = this.time.add(Date.MINUTE, 1);
21352 onDecrementMinutes: function()
21354 Roo.log('onDecrementMinutes');
21355 this.time = this.time.add(Date.MINUTE, -1);
21359 onTogglePeriod: function()
21361 Roo.log('onTogglePeriod');
21362 this.time = this.time.add(Date.HOUR, 12);
21369 Roo.apply(Roo.bootstrap.TimeField, {
21399 cls: 'btn btn-info ok',
21411 Roo.apply(Roo.bootstrap.TimeField, {
21415 cls: 'datepicker dropdown-menu',
21419 cls: 'datepicker-time',
21423 cls: 'table-condensed',
21425 Roo.bootstrap.TimeField.content,
21426 Roo.bootstrap.TimeField.footer
21445 * @class Roo.bootstrap.MonthField
21446 * @extends Roo.bootstrap.Input
21447 * Bootstrap MonthField class
21449 * @cfg {String} language default en
21452 * Create a new MonthField
21453 * @param {Object} config The config object
21456 Roo.bootstrap.MonthField = function(config){
21457 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
21462 * Fires when this field show.
21463 * @param {Roo.bootstrap.MonthField} this
21464 * @param {Mixed} date The date value
21469 * Fires when this field hide.
21470 * @param {Roo.bootstrap.MonthField} this
21471 * @param {Mixed} date The date value
21476 * Fires when select a date.
21477 * @param {Roo.bootstrap.MonthField} this
21478 * @param {String} oldvalue The old value
21479 * @param {String} newvalue The new value
21485 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
21487 onRender: function(ct, position)
21490 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
21492 this.language = this.language || 'en';
21493 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
21494 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
21496 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
21497 this.isInline = false;
21498 this.isInput = true;
21499 this.component = this.el.select('.add-on', true).first() || false;
21500 this.component = (this.component && this.component.length === 0) ? false : this.component;
21501 this.hasInput = this.component && this.inputEL().length;
21503 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
21505 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21507 this.picker().on('mousedown', this.onMousedown, this);
21508 this.picker().on('click', this.onClick, this);
21510 this.picker().addClass('datepicker-dropdown');
21512 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
21513 v.setStyle('width', '189px');
21520 if(this.isInline) {
21526 setValue: function(v, suppressEvent)
21528 var o = this.getValue();
21530 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
21534 if(suppressEvent !== true){
21535 this.fireEvent('select', this, o, v);
21540 getValue: function()
21545 onClick: function(e)
21547 e.stopPropagation();
21548 e.preventDefault();
21550 var target = e.getTarget();
21552 if(target.nodeName.toLowerCase() === 'i'){
21553 target = Roo.get(target).dom.parentNode;
21556 var nodeName = target.nodeName;
21557 var className = target.className;
21558 var html = target.innerHTML;
21560 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
21564 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
21566 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21572 picker : function()
21574 return this.pickerEl;
21577 fillMonths: function()
21580 var months = this.picker().select('>.datepicker-months td', true).first();
21582 months.dom.innerHTML = '';
21588 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
21591 months.createChild(month);
21600 if(typeof(this.vIndex) == 'undefined' && this.value.length){
21601 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
21604 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
21605 e.removeClass('active');
21607 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
21608 e.addClass('active');
21615 if(this.isInline) {
21619 this.picker().removeClass(['bottom', 'top']);
21621 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
21623 * place to the top of element!
21627 this.picker().addClass('top');
21628 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
21633 this.picker().addClass('bottom');
21635 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
21638 onFocus : function()
21640 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
21644 onBlur : function()
21646 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
21648 var d = this.inputEl().getValue();
21657 this.picker().show();
21658 this.picker().select('>.datepicker-months', true).first().show();
21662 this.fireEvent('show', this, this.date);
21667 if(this.isInline) {
21670 this.picker().hide();
21671 this.fireEvent('hide', this, this.date);
21675 onMousedown: function(e)
21677 e.stopPropagation();
21678 e.preventDefault();
21683 Roo.bootstrap.MonthField.superclass.keyup.call(this);
21687 fireKey: function(e)
21689 if (!this.picker().isVisible()){
21690 if (e.keyCode == 27) {// allow escape to hide and re-show picker
21701 e.preventDefault();
21705 dir = e.keyCode == 37 ? -1 : 1;
21707 this.vIndex = this.vIndex + dir;
21709 if(this.vIndex < 0){
21713 if(this.vIndex > 11){
21717 if(isNaN(this.vIndex)){
21721 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21727 dir = e.keyCode == 38 ? -1 : 1;
21729 this.vIndex = this.vIndex + dir * 4;
21731 if(this.vIndex < 0){
21735 if(this.vIndex > 11){
21739 if(isNaN(this.vIndex)){
21743 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21748 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
21749 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21753 e.preventDefault();
21756 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
21757 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21773 this.picker().remove();
21778 Roo.apply(Roo.bootstrap.MonthField, {
21797 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
21798 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
21803 Roo.apply(Roo.bootstrap.MonthField, {
21807 cls: 'datepicker dropdown-menu roo-dynamic',
21811 cls: 'datepicker-months',
21815 cls: 'table-condensed',
21817 Roo.bootstrap.DateField.content
21837 * @class Roo.bootstrap.CheckBox
21838 * @extends Roo.bootstrap.Input
21839 * Bootstrap CheckBox class
21841 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
21842 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
21843 * @cfg {String} boxLabel The text that appears beside the checkbox
21844 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
21845 * @cfg {Boolean} checked initnal the element
21846 * @cfg {Boolean} inline inline the element (default false)
21847 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
21848 * @cfg {String} tooltip label tooltip
21851 * Create a new CheckBox
21852 * @param {Object} config The config object
21855 Roo.bootstrap.CheckBox = function(config){
21856 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
21861 * Fires when the element is checked or unchecked.
21862 * @param {Roo.bootstrap.CheckBox} this This input
21863 * @param {Boolean} checked The new checked value
21868 * Fires when the element is click.
21869 * @param {Roo.bootstrap.CheckBox} this This input
21876 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
21878 inputType: 'checkbox',
21887 // checkbox success does not make any sense really..
21892 getAutoCreate : function()
21894 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
21900 cfg.cls = 'form-group form-check ' + this.inputType; //input-group
21903 cfg.cls += ' ' + this.inputType + '-inline form-check-inline';
21909 type : this.inputType,
21910 value : this.inputValue,
21911 cls : 'roo-' + this.inputType, //'form-box',
21912 placeholder : this.placeholder || ''
21916 if(this.inputType != 'radio'){
21920 cls : 'roo-hidden-value',
21921 value : this.checked ? this.inputValue : this.valueOff
21926 if (this.weight) { // Validity check?
21927 cfg.cls += " " + this.inputType + "-" + this.weight;
21930 if (this.disabled) {
21931 input.disabled=true;
21935 input.checked = this.checked;
21940 input.name = this.name;
21942 if(this.inputType != 'radio'){
21943 hidden.name = this.name;
21944 input.name = '_hidden_' + this.name;
21949 input.cls += ' input-' + this.size;
21954 ['xs','sm','md','lg'].map(function(size){
21955 if (settings[size]) {
21956 cfg.cls += ' col-' + size + '-' + settings[size];
21960 var inputblock = input;
21962 if (this.before || this.after) {
21965 cls : 'input-group',
21970 inputblock.cn.push({
21972 cls : 'input-group-addon',
21977 inputblock.cn.push(input);
21979 if(this.inputType != 'radio'){
21980 inputblock.cn.push(hidden);
21984 inputblock.cn.push({
21986 cls : 'input-group-addon',
21992 var boxLabelCfg = false;
21998 //'for': id, // box label is handled by onclick - so no for...
22000 html: this.boxLabel
22003 boxLabelCfg.tooltip = this.tooltip;
22009 if (align ==='left' && this.fieldLabel.length) {
22010 // Roo.log("left and has label");
22015 cls : 'control-label',
22016 html : this.fieldLabel
22027 cfg.cn[1].cn.push(boxLabelCfg);
22030 if(this.labelWidth > 12){
22031 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
22034 if(this.labelWidth < 13 && this.labelmd == 0){
22035 this.labelmd = this.labelWidth;
22038 if(this.labellg > 0){
22039 cfg.cn[0].cls += ' col-lg-' + this.labellg;
22040 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
22043 if(this.labelmd > 0){
22044 cfg.cn[0].cls += ' col-md-' + this.labelmd;
22045 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
22048 if(this.labelsm > 0){
22049 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
22050 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
22053 if(this.labelxs > 0){
22054 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
22055 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
22058 } else if ( this.fieldLabel.length) {
22059 // Roo.log(" label");
22063 tag: this.boxLabel ? 'span' : 'label',
22065 cls: 'control-label box-input-label',
22066 //cls : 'input-group-addon',
22067 html : this.fieldLabel
22074 cfg.cn.push(boxLabelCfg);
22079 // Roo.log(" no label && no align");
22080 cfg.cn = [ inputblock ] ;
22082 cfg.cn.push(boxLabelCfg);
22090 if(this.inputType != 'radio'){
22091 cfg.cn.push(hidden);
22099 * return the real input element.
22101 inputEl: function ()
22103 return this.el.select('input.roo-' + this.inputType,true).first();
22105 hiddenEl: function ()
22107 return this.el.select('input.roo-hidden-value',true).first();
22110 labelEl: function()
22112 return this.el.select('label.control-label',true).first();
22114 /* depricated... */
22118 return this.labelEl();
22121 boxLabelEl: function()
22123 return this.el.select('label.box-label',true).first();
22126 initEvents : function()
22128 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
22130 this.inputEl().on('click', this.onClick, this);
22132 if (this.boxLabel) {
22133 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
22136 this.startValue = this.getValue();
22139 Roo.bootstrap.CheckBox.register(this);
22143 onClick : function(e)
22145 if(this.fireEvent('click', this, e) !== false){
22146 this.setChecked(!this.checked);
22151 setChecked : function(state,suppressEvent)
22153 this.startValue = this.getValue();
22155 if(this.inputType == 'radio'){
22157 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22158 e.dom.checked = false;
22161 this.inputEl().dom.checked = true;
22163 this.inputEl().dom.value = this.inputValue;
22165 if(suppressEvent !== true){
22166 this.fireEvent('check', this, true);
22174 this.checked = state;
22176 this.inputEl().dom.checked = state;
22179 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
22181 if(suppressEvent !== true){
22182 this.fireEvent('check', this, state);
22188 getValue : function()
22190 if(this.inputType == 'radio'){
22191 return this.getGroupValue();
22194 return this.hiddenEl().dom.value;
22198 getGroupValue : function()
22200 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
22204 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
22207 setValue : function(v,suppressEvent)
22209 if(this.inputType == 'radio'){
22210 this.setGroupValue(v, suppressEvent);
22214 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
22219 setGroupValue : function(v, suppressEvent)
22221 this.startValue = this.getValue();
22223 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22224 e.dom.checked = false;
22226 if(e.dom.value == v){
22227 e.dom.checked = true;
22231 if(suppressEvent !== true){
22232 this.fireEvent('check', this, true);
22240 validate : function()
22242 if(this.getVisibilityEl().hasClass('hidden')){
22248 (this.inputType == 'radio' && this.validateRadio()) ||
22249 (this.inputType == 'checkbox' && this.validateCheckbox())
22255 this.markInvalid();
22259 validateRadio : function()
22261 if(this.getVisibilityEl().hasClass('hidden')){
22265 if(this.allowBlank){
22271 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22272 if(!e.dom.checked){
22284 validateCheckbox : function()
22287 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
22288 //return (this.getValue() == this.inputValue) ? true : false;
22291 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22299 for(var i in group){
22300 if(group[i].el.isVisible(true)){
22308 for(var i in group){
22313 r = (group[i].getValue() == group[i].inputValue) ? true : false;
22320 * Mark this field as valid
22322 markValid : function()
22326 this.fireEvent('valid', this);
22328 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22331 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
22338 if(this.inputType == 'radio'){
22339 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22340 var fg = e.findParent('.form-group', false, true);
22341 if (Roo.bootstrap.version == 3) {
22342 fg.removeClass([_this.invalidClass, _this.validClass]);
22343 fg.addClass(_this.validClass);
22345 fg.removeClass(['is-valid', 'is-invalid']);
22346 fg.addClass('is-valid');
22354 var fg = this.el.findParent('.form-group', false, true);
22355 if (Roo.bootstrap.version == 3) {
22356 fg.removeClass([this.invalidClass, this.validClass]);
22357 fg.addClass(this.validClass);
22359 fg.removeClass(['is-valid', 'is-invalid']);
22360 fg.addClass('is-valid');
22365 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22371 for(var i in group){
22372 var fg = group[i].el.findParent('.form-group', false, true);
22373 if (Roo.bootstrap.version == 3) {
22374 fg.removeClass([this.invalidClass, this.validClass]);
22375 fg.addClass(this.validClass);
22377 fg.removeClass(['is-valid', 'is-invalid']);
22378 fg.addClass('is-valid');
22384 * Mark this field as invalid
22385 * @param {String} msg The validation message
22387 markInvalid : function(msg)
22389 if(this.allowBlank){
22395 this.fireEvent('invalid', this, msg);
22397 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22400 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
22404 label.markInvalid();
22407 if(this.inputType == 'radio'){
22409 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22410 var fg = e.findParent('.form-group', false, true);
22411 if (Roo.bootstrap.version == 3) {
22412 fg.removeClass([_this.invalidClass, _this.validClass]);
22413 fg.addClass(_this.invalidClass);
22415 fg.removeClass(['is-invalid', 'is-valid']);
22416 fg.addClass('is-invalid');
22424 var fg = this.el.findParent('.form-group', false, true);
22425 if (Roo.bootstrap.version == 3) {
22426 fg.removeClass([_this.invalidClass, _this.validClass]);
22427 fg.addClass(_this.invalidClass);
22429 fg.removeClass(['is-invalid', 'is-valid']);
22430 fg.addClass('is-invalid');
22435 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22441 for(var i in group){
22442 var fg = group[i].el.findParent('.form-group', false, true);
22443 if (Roo.bootstrap.version == 3) {
22444 fg.removeClass([_this.invalidClass, _this.validClass]);
22445 fg.addClass(_this.invalidClass);
22447 fg.removeClass(['is-invalid', 'is-valid']);
22448 fg.addClass('is-invalid');
22454 clearInvalid : function()
22456 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
22458 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
22460 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22462 if (label && label.iconEl) {
22463 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
22464 label.iconEl.removeClass(['is-invalid', 'is-valid']);
22468 disable : function()
22470 if(this.inputType != 'radio'){
22471 Roo.bootstrap.CheckBox.superclass.disable.call(this);
22478 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22479 _this.getActionEl().addClass(this.disabledClass);
22480 e.dom.disabled = true;
22484 this.disabled = true;
22485 this.fireEvent("disable", this);
22489 enable : function()
22491 if(this.inputType != 'radio'){
22492 Roo.bootstrap.CheckBox.superclass.enable.call(this);
22499 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22500 _this.getActionEl().removeClass(this.disabledClass);
22501 e.dom.disabled = false;
22505 this.disabled = false;
22506 this.fireEvent("enable", this);
22510 setBoxLabel : function(v)
22515 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
22521 Roo.apply(Roo.bootstrap.CheckBox, {
22526 * register a CheckBox Group
22527 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
22529 register : function(checkbox)
22531 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
22532 this.groups[checkbox.groupId] = {};
22535 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
22539 this.groups[checkbox.groupId][checkbox.name] = checkbox;
22543 * fetch a CheckBox Group based on the group ID
22544 * @param {string} the group ID
22545 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
22547 get: function(groupId) {
22548 if (typeof(this.groups[groupId]) == 'undefined') {
22552 return this.groups[groupId] ;
22565 * @class Roo.bootstrap.Radio
22566 * @extends Roo.bootstrap.Component
22567 * Bootstrap Radio class
22568 * @cfg {String} boxLabel - the label associated
22569 * @cfg {String} value - the value of radio
22572 * Create a new Radio
22573 * @param {Object} config The config object
22575 Roo.bootstrap.Radio = function(config){
22576 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
22580 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
22586 getAutoCreate : function()
22590 cls : 'form-group radio',
22595 html : this.boxLabel
22603 initEvents : function()
22605 this.parent().register(this);
22607 this.el.on('click', this.onClick, this);
22611 onClick : function(e)
22613 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
22614 this.setChecked(true);
22618 setChecked : function(state, suppressEvent)
22620 this.parent().setValue(this.value, suppressEvent);
22624 setBoxLabel : function(v)
22629 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
22644 * @class Roo.bootstrap.SecurePass
22645 * @extends Roo.bootstrap.Input
22646 * Bootstrap SecurePass class
22650 * Create a new SecurePass
22651 * @param {Object} config The config object
22654 Roo.bootstrap.SecurePass = function (config) {
22655 // these go here, so the translation tool can replace them..
22657 PwdEmpty: "Please type a password, and then retype it to confirm.",
22658 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
22659 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
22660 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
22661 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
22662 FNInPwd: "Your password can't contain your first name. Please type a different password.",
22663 LNInPwd: "Your password can't contain your last name. Please type a different password.",
22664 TooWeak: "Your password is Too Weak."
22666 this.meterLabel = "Password strength:";
22667 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
22668 this.meterClass = [
22669 "roo-password-meter-tooweak",
22670 "roo-password-meter-weak",
22671 "roo-password-meter-medium",
22672 "roo-password-meter-strong",
22673 "roo-password-meter-grey"
22678 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
22681 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
22683 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
22685 * PwdEmpty: "Please type a password, and then retype it to confirm.",
22686 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
22687 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
22688 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
22689 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
22690 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
22691 * LNInPwd: "Your password can't contain your last name. Please type a different password."
22701 * @cfg {String/Object} Label for the strength meter (defaults to
22702 * 'Password strength:')
22707 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
22708 * ['Weak', 'Medium', 'Strong'])
22711 pwdStrengths: false,
22724 initEvents: function ()
22726 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
22728 if (this.el.is('input[type=password]') && Roo.isSafari) {
22729 this.el.on('keydown', this.SafariOnKeyDown, this);
22732 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
22735 onRender: function (ct, position)
22737 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
22738 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
22739 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
22741 this.trigger.createChild({
22746 cls: 'roo-password-meter-grey col-xs-12',
22749 //width: this.meterWidth + 'px'
22753 cls: 'roo-password-meter-text'
22759 if (this.hideTrigger) {
22760 this.trigger.setDisplayed(false);
22762 this.setSize(this.width || '', this.height || '');
22765 onDestroy: function ()
22767 if (this.trigger) {
22768 this.trigger.removeAllListeners();
22769 this.trigger.remove();
22772 this.wrap.remove();
22774 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
22777 checkStrength: function ()
22779 var pwd = this.inputEl().getValue();
22780 if (pwd == this._lastPwd) {
22785 if (this.ClientSideStrongPassword(pwd)) {
22787 } else if (this.ClientSideMediumPassword(pwd)) {
22789 } else if (this.ClientSideWeakPassword(pwd)) {
22795 Roo.log('strength1: ' + strength);
22797 //var pm = this.trigger.child('div/div/div').dom;
22798 var pm = this.trigger.child('div/div');
22799 pm.removeClass(this.meterClass);
22800 pm.addClass(this.meterClass[strength]);
22803 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22805 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
22807 this._lastPwd = pwd;
22811 Roo.bootstrap.SecurePass.superclass.reset.call(this);
22813 this._lastPwd = '';
22815 var pm = this.trigger.child('div/div');
22816 pm.removeClass(this.meterClass);
22817 pm.addClass('roo-password-meter-grey');
22820 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22823 this.inputEl().dom.type='password';
22826 validateValue: function (value)
22829 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
22832 if (value.length == 0) {
22833 if (this.allowBlank) {
22834 this.clearInvalid();
22838 this.markInvalid(this.errors.PwdEmpty);
22839 this.errorMsg = this.errors.PwdEmpty;
22847 if ('[\x21-\x7e]*'.match(value)) {
22848 this.markInvalid(this.errors.PwdBadChar);
22849 this.errorMsg = this.errors.PwdBadChar;
22852 if (value.length < 6) {
22853 this.markInvalid(this.errors.PwdShort);
22854 this.errorMsg = this.errors.PwdShort;
22857 if (value.length > 16) {
22858 this.markInvalid(this.errors.PwdLong);
22859 this.errorMsg = this.errors.PwdLong;
22863 if (this.ClientSideStrongPassword(value)) {
22865 } else if (this.ClientSideMediumPassword(value)) {
22867 } else if (this.ClientSideWeakPassword(value)) {
22874 if (strength < 2) {
22875 //this.markInvalid(this.errors.TooWeak);
22876 this.errorMsg = this.errors.TooWeak;
22881 console.log('strength2: ' + strength);
22883 //var pm = this.trigger.child('div/div/div').dom;
22885 var pm = this.trigger.child('div/div');
22886 pm.removeClass(this.meterClass);
22887 pm.addClass(this.meterClass[strength]);
22889 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22891 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
22893 this.errorMsg = '';
22897 CharacterSetChecks: function (type)
22900 this.fResult = false;
22903 isctype: function (character, type)
22906 case this.kCapitalLetter:
22907 if (character >= 'A' && character <= 'Z') {
22912 case this.kSmallLetter:
22913 if (character >= 'a' && character <= 'z') {
22919 if (character >= '0' && character <= '9') {
22924 case this.kPunctuation:
22925 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
22936 IsLongEnough: function (pwd, size)
22938 return !(pwd == null || isNaN(size) || pwd.length < size);
22941 SpansEnoughCharacterSets: function (word, nb)
22943 if (!this.IsLongEnough(word, nb))
22948 var characterSetChecks = new Array(
22949 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
22950 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
22953 for (var index = 0; index < word.length; ++index) {
22954 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
22955 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
22956 characterSetChecks[nCharSet].fResult = true;
22963 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
22964 if (characterSetChecks[nCharSet].fResult) {
22969 if (nCharSets < nb) {
22975 ClientSideStrongPassword: function (pwd)
22977 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
22980 ClientSideMediumPassword: function (pwd)
22982 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22985 ClientSideWeakPassword: function (pwd)
22987 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22990 })//<script type="text/javascript">
22993 * Based Ext JS Library 1.1.1
22994 * Copyright(c) 2006-2007, Ext JS, LLC.
23000 * @class Roo.HtmlEditorCore
23001 * @extends Roo.Component
23002 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
23004 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23007 Roo.HtmlEditorCore = function(config){
23010 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
23015 * @event initialize
23016 * Fires when the editor is fully initialized (including the iframe)
23017 * @param {Roo.HtmlEditorCore} this
23022 * Fires when the editor is first receives the focus. Any insertion must wait
23023 * until after this event.
23024 * @param {Roo.HtmlEditorCore} this
23028 * @event beforesync
23029 * Fires before the textarea is updated with content from the editor iframe. Return false
23030 * to cancel the sync.
23031 * @param {Roo.HtmlEditorCore} this
23032 * @param {String} html
23036 * @event beforepush
23037 * Fires before the iframe editor is updated with content from the textarea. Return false
23038 * to cancel the push.
23039 * @param {Roo.HtmlEditorCore} this
23040 * @param {String} html
23045 * Fires when the textarea is updated with content from the editor iframe.
23046 * @param {Roo.HtmlEditorCore} this
23047 * @param {String} html
23052 * Fires when the iframe editor is updated with content from the textarea.
23053 * @param {Roo.HtmlEditorCore} this
23054 * @param {String} html
23059 * @event editorevent
23060 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23061 * @param {Roo.HtmlEditorCore} this
23067 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
23069 // defaults : white / black...
23070 this.applyBlacklists();
23077 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
23081 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
23087 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23092 * @cfg {Number} height (in pixels)
23096 * @cfg {Number} width (in pixels)
23101 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23104 stylesheets: false,
23109 // private properties
23110 validationEvent : false,
23112 initialized : false,
23114 sourceEditMode : false,
23115 onFocus : Roo.emptyFn,
23117 hideMode:'offsets',
23121 // blacklist + whitelisted elements..
23128 * Protected method that will not generally be called directly. It
23129 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23130 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23132 getDocMarkup : function(){
23136 // inherit styels from page...??
23137 if (this.stylesheets === false) {
23139 Roo.get(document.head).select('style').each(function(node) {
23140 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23143 Roo.get(document.head).select('link').each(function(node) {
23144 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23147 } else if (!this.stylesheets.length) {
23149 st = '<style type="text/css">' +
23150 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23153 st = '<style type="text/css">' +
23158 st += '<style type="text/css">' +
23159 'IMG { cursor: pointer } ' +
23162 var cls = 'roo-htmleditor-body';
23164 if(this.bodyCls.length){
23165 cls += ' ' + this.bodyCls;
23168 return '<html><head>' + st +
23169 //<style type="text/css">' +
23170 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23172 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
23176 onRender : function(ct, position)
23179 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
23180 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
23183 this.el.dom.style.border = '0 none';
23184 this.el.dom.setAttribute('tabIndex', -1);
23185 this.el.addClass('x-hidden hide');
23189 if(Roo.isIE){ // fix IE 1px bogus margin
23190 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
23194 this.frameId = Roo.id();
23198 var iframe = this.owner.wrap.createChild({
23200 cls: 'form-control', // bootstrap..
23202 name: this.frameId,
23203 frameBorder : 'no',
23204 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
23209 this.iframe = iframe.dom;
23211 this.assignDocWin();
23213 this.doc.designMode = 'on';
23216 this.doc.write(this.getDocMarkup());
23220 var task = { // must defer to wait for browser to be ready
23222 //console.log("run task?" + this.doc.readyState);
23223 this.assignDocWin();
23224 if(this.doc.body || this.doc.readyState == 'complete'){
23226 this.doc.designMode="on";
23230 Roo.TaskMgr.stop(task);
23231 this.initEditor.defer(10, this);
23238 Roo.TaskMgr.start(task);
23243 onResize : function(w, h)
23245 Roo.log('resize: ' +w + ',' + h );
23246 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
23250 if(typeof w == 'number'){
23252 this.iframe.style.width = w + 'px';
23254 if(typeof h == 'number'){
23256 this.iframe.style.height = h + 'px';
23258 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
23265 * Toggles the editor between standard and source edit mode.
23266 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23268 toggleSourceEdit : function(sourceEditMode){
23270 this.sourceEditMode = sourceEditMode === true;
23272 if(this.sourceEditMode){
23274 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
23277 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
23278 //this.iframe.className = '';
23281 //this.setSize(this.owner.wrap.getSize());
23282 //this.fireEvent('editmodechange', this, this.sourceEditMode);
23289 * Protected method that will not generally be called directly. If you need/want
23290 * custom HTML cleanup, this is the method you should override.
23291 * @param {String} html The HTML to be cleaned
23292 * return {String} The cleaned HTML
23294 cleanHtml : function(html){
23295 html = String(html);
23296 if(html.length > 5){
23297 if(Roo.isSafari){ // strip safari nonsense
23298 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
23301 if(html == ' '){
23308 * HTML Editor -> Textarea
23309 * Protected method that will not generally be called directly. Syncs the contents
23310 * of the editor iframe with the textarea.
23312 syncValue : function(){
23313 if(this.initialized){
23314 var bd = (this.doc.body || this.doc.documentElement);
23315 //this.cleanUpPaste(); -- this is done else where and causes havoc..
23316 var html = bd.innerHTML;
23318 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
23319 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
23321 html = '<div style="'+m[0]+'">' + html + '</div>';
23324 html = this.cleanHtml(html);
23325 // fix up the special chars.. normaly like back quotes in word...
23326 // however we do not want to do this with chinese..
23327 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
23329 var cc = match.charCodeAt();
23331 // Get the character value, handling surrogate pairs
23332 if (match.length == 2) {
23333 // It's a surrogate pair, calculate the Unicode code point
23334 var high = match.charCodeAt(0) - 0xD800;
23335 var low = match.charCodeAt(1) - 0xDC00;
23336 cc = (high * 0x400) + low + 0x10000;
23338 (cc >= 0x4E00 && cc < 0xA000 ) ||
23339 (cc >= 0x3400 && cc < 0x4E00 ) ||
23340 (cc >= 0xf900 && cc < 0xfb00 )
23345 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
23346 return "&#" + cc + ";";
23353 if(this.owner.fireEvent('beforesync', this, html) !== false){
23354 this.el.dom.value = html;
23355 this.owner.fireEvent('sync', this, html);
23361 * Protected method that will not generally be called directly. Pushes the value of the textarea
23362 * into the iframe editor.
23364 pushValue : function(){
23365 if(this.initialized){
23366 var v = this.el.dom.value.trim();
23368 // if(v.length < 1){
23372 if(this.owner.fireEvent('beforepush', this, v) !== false){
23373 var d = (this.doc.body || this.doc.documentElement);
23375 this.cleanUpPaste();
23376 this.el.dom.value = d.innerHTML;
23377 this.owner.fireEvent('push', this, v);
23383 deferFocus : function(){
23384 this.focus.defer(10, this);
23388 focus : function(){
23389 if(this.win && !this.sourceEditMode){
23396 assignDocWin: function()
23398 var iframe = this.iframe;
23401 this.doc = iframe.contentWindow.document;
23402 this.win = iframe.contentWindow;
23404 // if (!Roo.get(this.frameId)) {
23407 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
23408 // this.win = Roo.get(this.frameId).dom.contentWindow;
23410 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
23414 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
23415 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
23420 initEditor : function(){
23421 //console.log("INIT EDITOR");
23422 this.assignDocWin();
23426 this.doc.designMode="on";
23428 this.doc.write(this.getDocMarkup());
23431 var dbody = (this.doc.body || this.doc.documentElement);
23432 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
23433 // this copies styles from the containing element into thsi one..
23434 // not sure why we need all of this..
23435 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
23437 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
23438 //ss['background-attachment'] = 'fixed'; // w3c
23439 dbody.bgProperties = 'fixed'; // ie
23440 //Roo.DomHelper.applyStyles(dbody, ss);
23441 Roo.EventManager.on(this.doc, {
23442 //'mousedown': this.onEditorEvent,
23443 'mouseup': this.onEditorEvent,
23444 'dblclick': this.onEditorEvent,
23445 'click': this.onEditorEvent,
23446 'keyup': this.onEditorEvent,
23451 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
23453 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
23454 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
23456 this.initialized = true;
23458 this.owner.fireEvent('initialize', this);
23463 onDestroy : function(){
23469 //for (var i =0; i < this.toolbars.length;i++) {
23470 // // fixme - ask toolbars for heights?
23471 // this.toolbars[i].onDestroy();
23474 //this.wrap.dom.innerHTML = '';
23475 //this.wrap.remove();
23480 onFirstFocus : function(){
23482 this.assignDocWin();
23485 this.activated = true;
23488 if(Roo.isGecko){ // prevent silly gecko errors
23490 var s = this.win.getSelection();
23491 if(!s.focusNode || s.focusNode.nodeType != 3){
23492 var r = s.getRangeAt(0);
23493 r.selectNodeContents((this.doc.body || this.doc.documentElement));
23498 this.execCmd('useCSS', true);
23499 this.execCmd('styleWithCSS', false);
23502 this.owner.fireEvent('activate', this);
23506 adjustFont: function(btn){
23507 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
23508 //if(Roo.isSafari){ // safari
23511 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
23512 if(Roo.isSafari){ // safari
23513 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
23514 v = (v < 10) ? 10 : v;
23515 v = (v > 48) ? 48 : v;
23516 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
23521 v = Math.max(1, v+adjust);
23523 this.execCmd('FontSize', v );
23526 onEditorEvent : function(e)
23528 this.owner.fireEvent('editorevent', this, e);
23529 // this.updateToolbar();
23530 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
23533 insertTag : function(tg)
23535 // could be a bit smarter... -> wrap the current selected tRoo..
23536 if (tg.toLowerCase() == 'span' ||
23537 tg.toLowerCase() == 'code' ||
23538 tg.toLowerCase() == 'sup' ||
23539 tg.toLowerCase() == 'sub'
23542 range = this.createRange(this.getSelection());
23543 var wrappingNode = this.doc.createElement(tg.toLowerCase());
23544 wrappingNode.appendChild(range.extractContents());
23545 range.insertNode(wrappingNode);
23552 this.execCmd("formatblock", tg);
23556 insertText : function(txt)
23560 var range = this.createRange();
23561 range.deleteContents();
23562 //alert(Sender.getAttribute('label'));
23564 range.insertNode(this.doc.createTextNode(txt));
23570 * Executes a Midas editor command on the editor document and performs necessary focus and
23571 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
23572 * @param {String} cmd The Midas command
23573 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
23575 relayCmd : function(cmd, value){
23577 this.execCmd(cmd, value);
23578 this.owner.fireEvent('editorevent', this);
23579 //this.updateToolbar();
23580 this.owner.deferFocus();
23584 * Executes a Midas editor command directly on the editor document.
23585 * For visual commands, you should use {@link #relayCmd} instead.
23586 * <b>This should only be called after the editor is initialized.</b>
23587 * @param {String} cmd The Midas command
23588 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
23590 execCmd : function(cmd, value){
23591 this.doc.execCommand(cmd, false, value === undefined ? null : value);
23598 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
23600 * @param {String} text | dom node..
23602 insertAtCursor : function(text)
23605 if(!this.activated){
23611 var r = this.doc.selection.createRange();
23622 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
23626 // from jquery ui (MIT licenced)
23628 var win = this.win;
23630 if (win.getSelection && win.getSelection().getRangeAt) {
23631 range = win.getSelection().getRangeAt(0);
23632 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
23633 range.insertNode(node);
23634 } else if (win.document.selection && win.document.selection.createRange) {
23635 // no firefox support
23636 var txt = typeof(text) == 'string' ? text : text.outerHTML;
23637 win.document.selection.createRange().pasteHTML(txt);
23639 // no firefox support
23640 var txt = typeof(text) == 'string' ? text : text.outerHTML;
23641 this.execCmd('InsertHTML', txt);
23650 mozKeyPress : function(e){
23652 var c = e.getCharCode(), cmd;
23655 c = String.fromCharCode(c).toLowerCase();
23669 this.cleanUpPaste.defer(100, this);
23677 e.preventDefault();
23685 fixKeys : function(){ // load time branching for fastest keydown performance
23687 return function(e){
23688 var k = e.getKey(), r;
23691 r = this.doc.selection.createRange();
23694 r.pasteHTML('    ');
23701 r = this.doc.selection.createRange();
23703 var target = r.parentElement();
23704 if(!target || target.tagName.toLowerCase() != 'li'){
23706 r.pasteHTML('<br />');
23712 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23713 this.cleanUpPaste.defer(100, this);
23719 }else if(Roo.isOpera){
23720 return function(e){
23721 var k = e.getKey();
23725 this.execCmd('InsertHTML','    ');
23728 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23729 this.cleanUpPaste.defer(100, this);
23734 }else if(Roo.isSafari){
23735 return function(e){
23736 var k = e.getKey();
23740 this.execCmd('InsertText','\t');
23744 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23745 this.cleanUpPaste.defer(100, this);
23753 getAllAncestors: function()
23755 var p = this.getSelectedNode();
23758 a.push(p); // push blank onto stack..
23759 p = this.getParentElement();
23763 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
23767 a.push(this.doc.body);
23771 lastSelNode : false,
23774 getSelection : function()
23776 this.assignDocWin();
23777 return Roo.isIE ? this.doc.selection : this.win.getSelection();
23780 getSelectedNode: function()
23782 // this may only work on Gecko!!!
23784 // should we cache this!!!!
23789 var range = this.createRange(this.getSelection()).cloneRange();
23792 var parent = range.parentElement();
23794 var testRange = range.duplicate();
23795 testRange.moveToElementText(parent);
23796 if (testRange.inRange(range)) {
23799 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
23802 parent = parent.parentElement;
23807 // is ancestor a text element.
23808 var ac = range.commonAncestorContainer;
23809 if (ac.nodeType == 3) {
23810 ac = ac.parentNode;
23813 var ar = ac.childNodes;
23816 var other_nodes = [];
23817 var has_other_nodes = false;
23818 for (var i=0;i<ar.length;i++) {
23819 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
23822 // fullly contained node.
23824 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
23829 // probably selected..
23830 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
23831 other_nodes.push(ar[i]);
23835 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
23840 has_other_nodes = true;
23842 if (!nodes.length && other_nodes.length) {
23843 nodes= other_nodes;
23845 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
23851 createRange: function(sel)
23853 // this has strange effects when using with
23854 // top toolbar - not sure if it's a great idea.
23855 //this.editor.contentWindow.focus();
23856 if (typeof sel != "undefined") {
23858 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
23860 return this.doc.createRange();
23863 return this.doc.createRange();
23866 getParentElement: function()
23869 this.assignDocWin();
23870 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
23872 var range = this.createRange(sel);
23875 var p = range.commonAncestorContainer;
23876 while (p.nodeType == 3) { // text node
23887 * Range intersection.. the hard stuff...
23891 * [ -- selected range --- ]
23895 * if end is before start or hits it. fail.
23896 * if start is after end or hits it fail.
23898 * if either hits (but other is outside. - then it's not
23904 // @see http://www.thismuchiknow.co.uk/?p=64.
23905 rangeIntersectsNode : function(range, node)
23907 var nodeRange = node.ownerDocument.createRange();
23909 nodeRange.selectNode(node);
23911 nodeRange.selectNodeContents(node);
23914 var rangeStartRange = range.cloneRange();
23915 rangeStartRange.collapse(true);
23917 var rangeEndRange = range.cloneRange();
23918 rangeEndRange.collapse(false);
23920 var nodeStartRange = nodeRange.cloneRange();
23921 nodeStartRange.collapse(true);
23923 var nodeEndRange = nodeRange.cloneRange();
23924 nodeEndRange.collapse(false);
23926 return rangeStartRange.compareBoundaryPoints(
23927 Range.START_TO_START, nodeEndRange) == -1 &&
23928 rangeEndRange.compareBoundaryPoints(
23929 Range.START_TO_START, nodeStartRange) == 1;
23933 rangeCompareNode : function(range, node)
23935 var nodeRange = node.ownerDocument.createRange();
23937 nodeRange.selectNode(node);
23939 nodeRange.selectNodeContents(node);
23943 range.collapse(true);
23945 nodeRange.collapse(true);
23947 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
23948 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
23950 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
23952 var nodeIsBefore = ss == 1;
23953 var nodeIsAfter = ee == -1;
23955 if (nodeIsBefore && nodeIsAfter) {
23958 if (!nodeIsBefore && nodeIsAfter) {
23959 return 1; //right trailed.
23962 if (nodeIsBefore && !nodeIsAfter) {
23963 return 2; // left trailed.
23969 // private? - in a new class?
23970 cleanUpPaste : function()
23972 // cleans up the whole document..
23973 Roo.log('cleanuppaste');
23975 this.cleanUpChildren(this.doc.body);
23976 var clean = this.cleanWordChars(this.doc.body.innerHTML);
23977 if (clean != this.doc.body.innerHTML) {
23978 this.doc.body.innerHTML = clean;
23983 cleanWordChars : function(input) {// change the chars to hex code
23984 var he = Roo.HtmlEditorCore;
23986 var output = input;
23987 Roo.each(he.swapCodes, function(sw) {
23988 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
23990 output = output.replace(swapper, sw[1]);
23997 cleanUpChildren : function (n)
23999 if (!n.childNodes.length) {
24002 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24003 this.cleanUpChild(n.childNodes[i]);
24010 cleanUpChild : function (node)
24013 //console.log(node);
24014 if (node.nodeName == "#text") {
24015 // clean up silly Windows -- stuff?
24018 if (node.nodeName == "#comment") {
24019 node.parentNode.removeChild(node);
24020 // clean up silly Windows -- stuff?
24023 var lcname = node.tagName.toLowerCase();
24024 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
24025 // whitelist of tags..
24027 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
24029 node.parentNode.removeChild(node);
24034 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
24036 // spans with no attributes - just remove them..
24037 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
24038 remove_keep_children = true;
24041 // remove <a name=....> as rendering on yahoo mailer is borked with this.
24042 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
24044 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
24045 // remove_keep_children = true;
24048 if (remove_keep_children) {
24049 this.cleanUpChildren(node);
24050 // inserts everything just before this node...
24051 while (node.childNodes.length) {
24052 var cn = node.childNodes[0];
24053 node.removeChild(cn);
24054 node.parentNode.insertBefore(cn, node);
24056 node.parentNode.removeChild(node);
24060 if (!node.attributes || !node.attributes.length) {
24065 this.cleanUpChildren(node);
24069 function cleanAttr(n,v)
24072 if (v.match(/^\./) || v.match(/^\//)) {
24075 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
24078 if (v.match(/^#/)) {
24081 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
24082 node.removeAttribute(n);
24086 var cwhite = this.cwhite;
24087 var cblack = this.cblack;
24089 function cleanStyle(n,v)
24091 if (v.match(/expression/)) { //XSS?? should we even bother..
24092 node.removeAttribute(n);
24096 var parts = v.split(/;/);
24099 Roo.each(parts, function(p) {
24100 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
24104 var l = p.split(':').shift().replace(/\s+/g,'');
24105 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
24107 if ( cwhite.length && cblack.indexOf(l) > -1) {
24108 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24109 //node.removeAttribute(n);
24113 // only allow 'c whitelisted system attributes'
24114 if ( cwhite.length && cwhite.indexOf(l) < 0) {
24115 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24116 //node.removeAttribute(n);
24126 if (clean.length) {
24127 node.setAttribute(n, clean.join(';'));
24129 node.removeAttribute(n);
24135 for (var i = node.attributes.length-1; i > -1 ; i--) {
24136 var a = node.attributes[i];
24139 if (a.name.toLowerCase().substr(0,2)=='on') {
24140 node.removeAttribute(a.name);
24143 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
24144 node.removeAttribute(a.name);
24147 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
24148 cleanAttr(a.name,a.value); // fixme..
24151 if (a.name == 'style') {
24152 cleanStyle(a.name,a.value);
24155 /// clean up MS crap..
24156 // tecnically this should be a list of valid class'es..
24159 if (a.name == 'class') {
24160 if (a.value.match(/^Mso/)) {
24161 node.removeAttribute('class');
24164 if (a.value.match(/^body$/)) {
24165 node.removeAttribute('class');
24176 this.cleanUpChildren(node);
24182 * Clean up MS wordisms...
24184 cleanWord : function(node)
24187 this.cleanWord(this.doc.body);
24192 node.nodeName == 'SPAN' &&
24193 !node.hasAttributes() &&
24194 node.childNodes.length == 1 &&
24195 node.firstChild.nodeName == "#text"
24197 var textNode = node.firstChild;
24198 node.removeChild(textNode);
24199 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24200 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
24202 node.parentNode.insertBefore(textNode, node);
24203 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24204 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
24206 node.parentNode.removeChild(node);
24209 if (node.nodeName == "#text") {
24210 // clean up silly Windows -- stuff?
24213 if (node.nodeName == "#comment") {
24214 node.parentNode.removeChild(node);
24215 // clean up silly Windows -- stuff?
24219 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
24220 node.parentNode.removeChild(node);
24223 //Roo.log(node.tagName);
24224 // remove - but keep children..
24225 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
24226 //Roo.log('-- removed');
24227 while (node.childNodes.length) {
24228 var cn = node.childNodes[0];
24229 node.removeChild(cn);
24230 node.parentNode.insertBefore(cn, node);
24231 // move node to parent - and clean it..
24232 this.cleanWord(cn);
24234 node.parentNode.removeChild(node);
24235 /// no need to iterate chidlren = it's got none..
24236 //this.iterateChildren(node, this.cleanWord);
24240 if (node.className.length) {
24242 var cn = node.className.split(/\W+/);
24244 Roo.each(cn, function(cls) {
24245 if (cls.match(/Mso[a-zA-Z]+/)) {
24250 node.className = cna.length ? cna.join(' ') : '';
24252 node.removeAttribute("class");
24256 if (node.hasAttribute("lang")) {
24257 node.removeAttribute("lang");
24260 if (node.hasAttribute("style")) {
24262 var styles = node.getAttribute("style").split(";");
24264 Roo.each(styles, function(s) {
24265 if (!s.match(/:/)) {
24268 var kv = s.split(":");
24269 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
24272 // what ever is left... we allow.
24275 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
24276 if (!nstyle.length) {
24277 node.removeAttribute('style');
24280 this.iterateChildren(node, this.cleanWord);
24286 * iterateChildren of a Node, calling fn each time, using this as the scole..
24287 * @param {DomNode} node node to iterate children of.
24288 * @param {Function} fn method of this class to call on each item.
24290 iterateChildren : function(node, fn)
24292 if (!node.childNodes.length) {
24295 for (var i = node.childNodes.length-1; i > -1 ; i--) {
24296 fn.call(this, node.childNodes[i])
24302 * cleanTableWidths.
24304 * Quite often pasting from word etc.. results in tables with column and widths.
24305 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
24308 cleanTableWidths : function(node)
24313 this.cleanTableWidths(this.doc.body);
24318 if (node.nodeName == "#text" || node.nodeName == "#comment") {
24321 Roo.log(node.tagName);
24322 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
24323 this.iterateChildren(node, this.cleanTableWidths);
24326 if (node.hasAttribute('width')) {
24327 node.removeAttribute('width');
24331 if (node.hasAttribute("style")) {
24334 var styles = node.getAttribute("style").split(";");
24336 Roo.each(styles, function(s) {
24337 if (!s.match(/:/)) {
24340 var kv = s.split(":");
24341 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
24344 // what ever is left... we allow.
24347 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
24348 if (!nstyle.length) {
24349 node.removeAttribute('style');
24353 this.iterateChildren(node, this.cleanTableWidths);
24361 domToHTML : function(currentElement, depth, nopadtext) {
24363 depth = depth || 0;
24364 nopadtext = nopadtext || false;
24366 if (!currentElement) {
24367 return this.domToHTML(this.doc.body);
24370 //Roo.log(currentElement);
24372 var allText = false;
24373 var nodeName = currentElement.nodeName;
24374 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
24376 if (nodeName == '#text') {
24378 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
24383 if (nodeName != 'BODY') {
24386 // Prints the node tagName, such as <A>, <IMG>, etc
24389 for(i = 0; i < currentElement.attributes.length;i++) {
24391 var aname = currentElement.attributes.item(i).name;
24392 if (!currentElement.attributes.item(i).value.length) {
24395 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
24398 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
24407 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
24410 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
24415 // Traverse the tree
24417 var currentElementChild = currentElement.childNodes.item(i);
24418 var allText = true;
24419 var innerHTML = '';
24421 while (currentElementChild) {
24422 // Formatting code (indent the tree so it looks nice on the screen)
24423 var nopad = nopadtext;
24424 if (lastnode == 'SPAN') {
24428 if (currentElementChild.nodeName == '#text') {
24429 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
24430 toadd = nopadtext ? toadd : toadd.trim();
24431 if (!nopad && toadd.length > 80) {
24432 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
24434 innerHTML += toadd;
24437 currentElementChild = currentElement.childNodes.item(i);
24443 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
24445 // Recursively traverse the tree structure of the child node
24446 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
24447 lastnode = currentElementChild.nodeName;
24449 currentElementChild=currentElement.childNodes.item(i);
24455 // The remaining code is mostly for formatting the tree
24456 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
24461 ret+= "</"+tagName+">";
24467 applyBlacklists : function()
24469 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
24470 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
24474 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
24475 if (b.indexOf(tag) > -1) {
24478 this.white.push(tag);
24482 Roo.each(w, function(tag) {
24483 if (b.indexOf(tag) > -1) {
24486 if (this.white.indexOf(tag) > -1) {
24489 this.white.push(tag);
24494 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
24495 if (w.indexOf(tag) > -1) {
24498 this.black.push(tag);
24502 Roo.each(b, function(tag) {
24503 if (w.indexOf(tag) > -1) {
24506 if (this.black.indexOf(tag) > -1) {
24509 this.black.push(tag);
24514 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
24515 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
24519 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
24520 if (b.indexOf(tag) > -1) {
24523 this.cwhite.push(tag);
24527 Roo.each(w, function(tag) {
24528 if (b.indexOf(tag) > -1) {
24531 if (this.cwhite.indexOf(tag) > -1) {
24534 this.cwhite.push(tag);
24539 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
24540 if (w.indexOf(tag) > -1) {
24543 this.cblack.push(tag);
24547 Roo.each(b, function(tag) {
24548 if (w.indexOf(tag) > -1) {
24551 if (this.cblack.indexOf(tag) > -1) {
24554 this.cblack.push(tag);
24559 setStylesheets : function(stylesheets)
24561 if(typeof(stylesheets) == 'string'){
24562 Roo.get(this.iframe.contentDocument.head).createChild({
24564 rel : 'stylesheet',
24573 Roo.each(stylesheets, function(s) {
24578 Roo.get(_this.iframe.contentDocument.head).createChild({
24580 rel : 'stylesheet',
24589 removeStylesheets : function()
24593 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
24598 setStyle : function(style)
24600 Roo.get(this.iframe.contentDocument.head).createChild({
24609 // hide stuff that is not compatible
24623 * @event specialkey
24627 * @cfg {String} fieldClass @hide
24630 * @cfg {String} focusClass @hide
24633 * @cfg {String} autoCreate @hide
24636 * @cfg {String} inputType @hide
24639 * @cfg {String} invalidClass @hide
24642 * @cfg {String} invalidText @hide
24645 * @cfg {String} msgFx @hide
24648 * @cfg {String} validateOnBlur @hide
24652 Roo.HtmlEditorCore.white = [
24653 'area', 'br', 'img', 'input', 'hr', 'wbr',
24655 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24656 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24657 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24658 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24659 'table', 'ul', 'xmp',
24661 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24664 'dir', 'menu', 'ol', 'ul', 'dl',
24670 Roo.HtmlEditorCore.black = [
24671 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24673 'base', 'basefont', 'bgsound', 'blink', 'body',
24674 'frame', 'frameset', 'head', 'html', 'ilayer',
24675 'iframe', 'layer', 'link', 'meta', 'object',
24676 'script', 'style' ,'title', 'xml' // clean later..
24678 Roo.HtmlEditorCore.clean = [
24679 'script', 'style', 'title', 'xml'
24681 Roo.HtmlEditorCore.remove = [
24686 Roo.HtmlEditorCore.ablack = [
24690 Roo.HtmlEditorCore.aclean = [
24691 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24695 Roo.HtmlEditorCore.pwhite= [
24696 'http', 'https', 'mailto'
24699 // white listed style attributes.
24700 Roo.HtmlEditorCore.cwhite= [
24701 // 'text-align', /// default is to allow most things..
24707 // black listed style attributes.
24708 Roo.HtmlEditorCore.cblack= [
24709 // 'font-size' -- this can be set by the project
24713 Roo.HtmlEditorCore.swapCodes =[
24732 * @class Roo.bootstrap.HtmlEditor
24733 * @extends Roo.bootstrap.TextArea
24734 * Bootstrap HtmlEditor class
24737 * Create a new HtmlEditor
24738 * @param {Object} config The config object
24741 Roo.bootstrap.HtmlEditor = function(config){
24742 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
24743 if (!this.toolbars) {
24744 this.toolbars = [];
24747 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
24750 * @event initialize
24751 * Fires when the editor is fully initialized (including the iframe)
24752 * @param {HtmlEditor} this
24757 * Fires when the editor is first receives the focus. Any insertion must wait
24758 * until after this event.
24759 * @param {HtmlEditor} this
24763 * @event beforesync
24764 * Fires before the textarea is updated with content from the editor iframe. Return false
24765 * to cancel the sync.
24766 * @param {HtmlEditor} this
24767 * @param {String} html
24771 * @event beforepush
24772 * Fires before the iframe editor is updated with content from the textarea. Return false
24773 * to cancel the push.
24774 * @param {HtmlEditor} this
24775 * @param {String} html
24780 * Fires when the textarea is updated with content from the editor iframe.
24781 * @param {HtmlEditor} this
24782 * @param {String} html
24787 * Fires when the iframe editor is updated with content from the textarea.
24788 * @param {HtmlEditor} this
24789 * @param {String} html
24793 * @event editmodechange
24794 * Fires when the editor switches edit modes
24795 * @param {HtmlEditor} this
24796 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
24798 editmodechange: true,
24800 * @event editorevent
24801 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
24802 * @param {HtmlEditor} this
24806 * @event firstfocus
24807 * Fires when on first focus - needed by toolbars..
24808 * @param {HtmlEditor} this
24813 * Auto save the htmlEditor value as a file into Events
24814 * @param {HtmlEditor} this
24818 * @event savedpreview
24819 * preview the saved version of htmlEditor
24820 * @param {HtmlEditor} this
24827 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
24831 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
24836 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
24841 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
24846 * @cfg {Number} height (in pixels)
24850 * @cfg {Number} width (in pixels)
24855 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
24858 stylesheets: false,
24863 // private properties
24864 validationEvent : false,
24866 initialized : false,
24869 onFocus : Roo.emptyFn,
24871 hideMode:'offsets',
24873 tbContainer : false,
24877 toolbarContainer :function() {
24878 return this.wrap.select('.x-html-editor-tb',true).first();
24882 * Protected method that will not generally be called directly. It
24883 * is called when the editor creates its toolbar. Override this method if you need to
24884 * add custom toolbar buttons.
24885 * @param {HtmlEditor} editor
24887 createToolbar : function(){
24888 Roo.log('renewing');
24889 Roo.log("create toolbars");
24891 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
24892 this.toolbars[0].render(this.toolbarContainer());
24896 // if (!editor.toolbars || !editor.toolbars.length) {
24897 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
24900 // for (var i =0 ; i < editor.toolbars.length;i++) {
24901 // editor.toolbars[i] = Roo.factory(
24902 // typeof(editor.toolbars[i]) == 'string' ?
24903 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
24904 // Roo.bootstrap.HtmlEditor);
24905 // editor.toolbars[i].init(editor);
24911 onRender : function(ct, position)
24913 // Roo.log("Call onRender: " + this.xtype);
24915 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
24917 this.wrap = this.inputEl().wrap({
24918 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24921 this.editorcore.onRender(ct, position);
24923 if (this.resizable) {
24924 this.resizeEl = new Roo.Resizable(this.wrap, {
24928 minHeight : this.height,
24929 height: this.height,
24930 handles : this.resizable,
24933 resize : function(r, w, h) {
24934 _t.onResize(w,h); // -something
24940 this.createToolbar(this);
24943 if(!this.width && this.resizable){
24944 this.setSize(this.wrap.getSize());
24946 if (this.resizeEl) {
24947 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
24948 // should trigger onReize..
24954 onResize : function(w, h)
24956 Roo.log('resize: ' +w + ',' + h );
24957 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
24961 if(this.inputEl() ){
24962 if(typeof w == 'number'){
24963 var aw = w - this.wrap.getFrameWidth('lr');
24964 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
24967 if(typeof h == 'number'){
24968 var tbh = -11; // fixme it needs to tool bar size!
24969 for (var i =0; i < this.toolbars.length;i++) {
24970 // fixme - ask toolbars for heights?
24971 tbh += this.toolbars[i].el.getHeight();
24972 //if (this.toolbars[i].footer) {
24973 // tbh += this.toolbars[i].footer.el.getHeight();
24981 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24982 ah -= 5; // knock a few pixes off for look..
24983 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
24987 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
24988 this.editorcore.onResize(ew,eh);
24993 * Toggles the editor between standard and source edit mode.
24994 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24996 toggleSourceEdit : function(sourceEditMode)
24998 this.editorcore.toggleSourceEdit(sourceEditMode);
25000 if(this.editorcore.sourceEditMode){
25001 Roo.log('editor - showing textarea');
25004 // Roo.log(this.syncValue());
25006 this.inputEl().removeClass(['hide', 'x-hidden']);
25007 this.inputEl().dom.removeAttribute('tabIndex');
25008 this.inputEl().focus();
25010 Roo.log('editor - hiding textarea');
25012 // Roo.log(this.pushValue());
25015 this.inputEl().addClass(['hide', 'x-hidden']);
25016 this.inputEl().dom.setAttribute('tabIndex', -1);
25017 //this.deferFocus();
25020 if(this.resizable){
25021 this.setSize(this.wrap.getSize());
25024 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
25027 // private (for BoxComponent)
25028 adjustSize : Roo.BoxComponent.prototype.adjustSize,
25030 // private (for BoxComponent)
25031 getResizeEl : function(){
25035 // private (for BoxComponent)
25036 getPositionEl : function(){
25041 initEvents : function(){
25042 this.originalValue = this.getValue();
25046 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25049 // markInvalid : Roo.emptyFn,
25051 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25054 // clearInvalid : Roo.emptyFn,
25056 setValue : function(v){
25057 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
25058 this.editorcore.pushValue();
25063 deferFocus : function(){
25064 this.focus.defer(10, this);
25068 focus : function(){
25069 this.editorcore.focus();
25075 onDestroy : function(){
25081 for (var i =0; i < this.toolbars.length;i++) {
25082 // fixme - ask toolbars for heights?
25083 this.toolbars[i].onDestroy();
25086 this.wrap.dom.innerHTML = '';
25087 this.wrap.remove();
25092 onFirstFocus : function(){
25093 //Roo.log("onFirstFocus");
25094 this.editorcore.onFirstFocus();
25095 for (var i =0; i < this.toolbars.length;i++) {
25096 this.toolbars[i].onFirstFocus();
25102 syncValue : function()
25104 this.editorcore.syncValue();
25107 pushValue : function()
25109 this.editorcore.pushValue();
25113 // hide stuff that is not compatible
25127 * @event specialkey
25131 * @cfg {String} fieldClass @hide
25134 * @cfg {String} focusClass @hide
25137 * @cfg {String} autoCreate @hide
25140 * @cfg {String} inputType @hide
25144 * @cfg {String} invalidText @hide
25147 * @cfg {String} msgFx @hide
25150 * @cfg {String} validateOnBlur @hide
25159 Roo.namespace('Roo.bootstrap.htmleditor');
25161 * @class Roo.bootstrap.HtmlEditorToolbar1
25167 new Roo.bootstrap.HtmlEditor({
25170 new Roo.bootstrap.HtmlEditorToolbar1({
25171 disable : { fonts: 1 , format: 1, ..., ... , ...],
25177 * @cfg {Object} disable List of elements to disable..
25178 * @cfg {Array} btns List of additional buttons.
25182 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
25185 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
25188 Roo.apply(this, config);
25190 // default disabled, based on 'good practice'..
25191 this.disable = this.disable || {};
25192 Roo.applyIf(this.disable, {
25195 specialElements : true
25197 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
25199 this.editor = config.editor;
25200 this.editorcore = config.editor.editorcore;
25202 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
25204 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25205 // dont call parent... till later.
25207 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
25212 editorcore : false,
25217 "h1","h2","h3","h4","h5","h6",
25219 "abbr", "acronym", "address", "cite", "samp", "var",
25223 onRender : function(ct, position)
25225 // Roo.log("Call onRender: " + this.xtype);
25227 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
25229 this.el.dom.style.marginBottom = '0';
25231 var editorcore = this.editorcore;
25232 var editor= this.editor;
25235 var btn = function(id,cmd , toggle, handler, html){
25237 var event = toggle ? 'toggle' : 'click';
25242 xns: Roo.bootstrap,
25246 enableToggle:toggle !== false,
25248 pressed : toggle ? false : null,
25251 a.listeners[toggle ? 'toggle' : 'click'] = function() {
25252 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
25258 // var cb_box = function...
25263 xns: Roo.bootstrap,
25268 xns: Roo.bootstrap,
25272 Roo.each(this.formats, function(f) {
25273 style.menu.items.push({
25275 xns: Roo.bootstrap,
25276 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
25281 editorcore.insertTag(this.tagname);
25288 children.push(style);
25290 btn('bold',false,true);
25291 btn('italic',false,true);
25292 btn('align-left', 'justifyleft',true);
25293 btn('align-center', 'justifycenter',true);
25294 btn('align-right' , 'justifyright',true);
25295 btn('link', false, false, function(btn) {
25296 //Roo.log("create link?");
25297 var url = prompt(this.createLinkText, this.defaultLinkValue);
25298 if(url && url != 'http:/'+'/'){
25299 this.editorcore.relayCmd('createlink', url);
25302 btn('list','insertunorderedlist',true);
25303 btn('pencil', false,true, function(btn){
25305 this.toggleSourceEdit(btn.pressed);
25308 if (this.editor.btns.length > 0) {
25309 for (var i = 0; i<this.editor.btns.length; i++) {
25310 children.push(this.editor.btns[i]);
25318 xns: Roo.bootstrap,
25323 xns: Roo.bootstrap,
25328 cog.menu.items.push({
25330 xns: Roo.bootstrap,
25331 html : Clean styles,
25336 editorcore.insertTag(this.tagname);
25345 this.xtype = 'NavSimplebar';
25347 for(var i=0;i< children.length;i++) {
25349 this.buttons.add(this.addxtypeChild(children[i]));
25353 editor.on('editorevent', this.updateToolbar, this);
25355 onBtnClick : function(id)
25357 this.editorcore.relayCmd(id);
25358 this.editorcore.focus();
25362 * Protected method that will not generally be called directly. It triggers
25363 * a toolbar update by reading the markup state of the current selection in the editor.
25365 updateToolbar: function(){
25367 if(!this.editorcore.activated){
25368 this.editor.onFirstFocus(); // is this neeed?
25372 var btns = this.buttons;
25373 var doc = this.editorcore.doc;
25374 btns.get('bold').setActive(doc.queryCommandState('bold'));
25375 btns.get('italic').setActive(doc.queryCommandState('italic'));
25376 //btns.get('underline').setActive(doc.queryCommandState('underline'));
25378 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
25379 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
25380 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
25382 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
25383 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
25386 var ans = this.editorcore.getAllAncestors();
25387 if (this.formatCombo) {
25390 var store = this.formatCombo.store;
25391 this.formatCombo.setValue("");
25392 for (var i =0; i < ans.length;i++) {
25393 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25395 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25403 // hides menus... - so this cant be on a menu...
25404 Roo.bootstrap.MenuMgr.hideAll();
25406 Roo.bootstrap.MenuMgr.hideAll();
25407 //this.editorsyncValue();
25409 onFirstFocus: function() {
25410 this.buttons.each(function(item){
25414 toggleSourceEdit : function(sourceEditMode){
25417 if(sourceEditMode){
25418 Roo.log("disabling buttons");
25419 this.buttons.each( function(item){
25420 if(item.cmd != 'pencil'){
25426 Roo.log("enabling buttons");
25427 if(this.editorcore.initialized){
25428 this.buttons.each( function(item){
25434 Roo.log("calling toggole on editor");
25435 // tell the editor that it's been pressed..
25436 this.editor.toggleSourceEdit(sourceEditMode);
25446 * @class Roo.bootstrap.Table.AbstractSelectionModel
25447 * @extends Roo.util.Observable
25448 * Abstract base class for grid SelectionModels. It provides the interface that should be
25449 * implemented by descendant classes. This class should not be directly instantiated.
25452 Roo.bootstrap.Table.AbstractSelectionModel = function(){
25453 this.locked = false;
25454 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
25458 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
25459 /** @ignore Called by the grid automatically. Do not call directly. */
25460 init : function(grid){
25466 * Locks the selections.
25469 this.locked = true;
25473 * Unlocks the selections.
25475 unlock : function(){
25476 this.locked = false;
25480 * Returns true if the selections are locked.
25481 * @return {Boolean}
25483 isLocked : function(){
25484 return this.locked;
25488 initEvents : function ()
25494 * @extends Roo.bootstrap.Table.AbstractSelectionModel
25495 * @class Roo.bootstrap.Table.RowSelectionModel
25496 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
25497 * It supports multiple selections and keyboard selection/navigation.
25499 * @param {Object} config
25502 Roo.bootstrap.Table.RowSelectionModel = function(config){
25503 Roo.apply(this, config);
25504 this.selections = new Roo.util.MixedCollection(false, function(o){
25509 this.lastActive = false;
25513 * @event selectionchange
25514 * Fires when the selection changes
25515 * @param {SelectionModel} this
25517 "selectionchange" : true,
25519 * @event afterselectionchange
25520 * Fires after the selection changes (eg. by key press or clicking)
25521 * @param {SelectionModel} this
25523 "afterselectionchange" : true,
25525 * @event beforerowselect
25526 * Fires when a row is selected being selected, return false to cancel.
25527 * @param {SelectionModel} this
25528 * @param {Number} rowIndex The selected index
25529 * @param {Boolean} keepExisting False if other selections will be cleared
25531 "beforerowselect" : true,
25534 * Fires when a row is selected.
25535 * @param {SelectionModel} this
25536 * @param {Number} rowIndex The selected index
25537 * @param {Roo.data.Record} r The record
25539 "rowselect" : true,
25541 * @event rowdeselect
25542 * Fires when a row is deselected.
25543 * @param {SelectionModel} this
25544 * @param {Number} rowIndex The selected index
25546 "rowdeselect" : true
25548 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
25549 this.locked = false;
25552 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
25554 * @cfg {Boolean} singleSelect
25555 * True to allow selection of only one row at a time (defaults to false)
25557 singleSelect : false,
25560 initEvents : function()
25563 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
25564 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
25565 //}else{ // allow click to work like normal
25566 // this.grid.on("rowclick", this.handleDragableRowClick, this);
25568 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
25569 this.grid.on("rowclick", this.handleMouseDown, this);
25571 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
25572 "up" : function(e){
25574 this.selectPrevious(e.shiftKey);
25575 }else if(this.last !== false && this.lastActive !== false){
25576 var last = this.last;
25577 this.selectRange(this.last, this.lastActive-1);
25578 this.grid.getView().focusRow(this.lastActive);
25579 if(last !== false){
25583 this.selectFirstRow();
25585 this.fireEvent("afterselectionchange", this);
25587 "down" : function(e){
25589 this.selectNext(e.shiftKey);
25590 }else if(this.last !== false && this.lastActive !== false){
25591 var last = this.last;
25592 this.selectRange(this.last, this.lastActive+1);
25593 this.grid.getView().focusRow(this.lastActive);
25594 if(last !== false){
25598 this.selectFirstRow();
25600 this.fireEvent("afterselectionchange", this);
25604 this.grid.store.on('load', function(){
25605 this.selections.clear();
25608 var view = this.grid.view;
25609 view.on("refresh", this.onRefresh, this);
25610 view.on("rowupdated", this.onRowUpdated, this);
25611 view.on("rowremoved", this.onRemove, this);
25616 onRefresh : function()
25618 var ds = this.grid.store, i, v = this.grid.view;
25619 var s = this.selections;
25620 s.each(function(r){
25621 if((i = ds.indexOfId(r.id)) != -1){
25630 onRemove : function(v, index, r){
25631 this.selections.remove(r);
25635 onRowUpdated : function(v, index, r){
25636 if(this.isSelected(r)){
25637 v.onRowSelect(index);
25643 * @param {Array} records The records to select
25644 * @param {Boolean} keepExisting (optional) True to keep existing selections
25646 selectRecords : function(records, keepExisting)
25649 this.clearSelections();
25651 var ds = this.grid.store;
25652 for(var i = 0, len = records.length; i < len; i++){
25653 this.selectRow(ds.indexOf(records[i]), true);
25658 * Gets the number of selected rows.
25661 getCount : function(){
25662 return this.selections.length;
25666 * Selects the first row in the grid.
25668 selectFirstRow : function(){
25673 * Select the last row.
25674 * @param {Boolean} keepExisting (optional) True to keep existing selections
25676 selectLastRow : function(keepExisting){
25677 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
25678 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
25682 * Selects the row immediately following the last selected row.
25683 * @param {Boolean} keepExisting (optional) True to keep existing selections
25685 selectNext : function(keepExisting)
25687 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
25688 this.selectRow(this.last+1, keepExisting);
25689 this.grid.getView().focusRow(this.last);
25694 * Selects the row that precedes the last selected row.
25695 * @param {Boolean} keepExisting (optional) True to keep existing selections
25697 selectPrevious : function(keepExisting){
25699 this.selectRow(this.last-1, keepExisting);
25700 this.grid.getView().focusRow(this.last);
25705 * Returns the selected records
25706 * @return {Array} Array of selected records
25708 getSelections : function(){
25709 return [].concat(this.selections.items);
25713 * Returns the first selected record.
25716 getSelected : function(){
25717 return this.selections.itemAt(0);
25722 * Clears all selections.
25724 clearSelections : function(fast)
25730 var ds = this.grid.store;
25731 var s = this.selections;
25732 s.each(function(r){
25733 this.deselectRow(ds.indexOfId(r.id));
25737 this.selections.clear();
25744 * Selects all rows.
25746 selectAll : function(){
25750 this.selections.clear();
25751 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
25752 this.selectRow(i, true);
25757 * Returns True if there is a selection.
25758 * @return {Boolean}
25760 hasSelection : function(){
25761 return this.selections.length > 0;
25765 * Returns True if the specified row is selected.
25766 * @param {Number/Record} record The record or index of the record to check
25767 * @return {Boolean}
25769 isSelected : function(index){
25770 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
25771 return (r && this.selections.key(r.id) ? true : false);
25775 * Returns True if the specified record id is selected.
25776 * @param {String} id The id of record to check
25777 * @return {Boolean}
25779 isIdSelected : function(id){
25780 return (this.selections.key(id) ? true : false);
25785 handleMouseDBClick : function(e, t){
25789 handleMouseDown : function(e, t)
25791 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
25792 if(this.isLocked() || rowIndex < 0 ){
25795 if(e.shiftKey && this.last !== false){
25796 var last = this.last;
25797 this.selectRange(last, rowIndex, e.ctrlKey);
25798 this.last = last; // reset the last
25802 var isSelected = this.isSelected(rowIndex);
25803 //Roo.log("select row:" + rowIndex);
25805 this.deselectRow(rowIndex);
25807 this.selectRow(rowIndex, true);
25811 if(e.button !== 0 && isSelected){
25812 alert('rowIndex 2: ' + rowIndex);
25813 view.focusRow(rowIndex);
25814 }else if(e.ctrlKey && isSelected){
25815 this.deselectRow(rowIndex);
25816 }else if(!isSelected){
25817 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
25818 view.focusRow(rowIndex);
25822 this.fireEvent("afterselectionchange", this);
25825 handleDragableRowClick : function(grid, rowIndex, e)
25827 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
25828 this.selectRow(rowIndex, false);
25829 grid.view.focusRow(rowIndex);
25830 this.fireEvent("afterselectionchange", this);
25835 * Selects multiple rows.
25836 * @param {Array} rows Array of the indexes of the row to select
25837 * @param {Boolean} keepExisting (optional) True to keep existing selections
25839 selectRows : function(rows, keepExisting){
25841 this.clearSelections();
25843 for(var i = 0, len = rows.length; i < len; i++){
25844 this.selectRow(rows[i], true);
25849 * Selects a range of rows. All rows in between startRow and endRow are also selected.
25850 * @param {Number} startRow The index of the first row in the range
25851 * @param {Number} endRow The index of the last row in the range
25852 * @param {Boolean} keepExisting (optional) True to retain existing selections
25854 selectRange : function(startRow, endRow, keepExisting){
25859 this.clearSelections();
25861 if(startRow <= endRow){
25862 for(var i = startRow; i <= endRow; i++){
25863 this.selectRow(i, true);
25866 for(var i = startRow; i >= endRow; i--){
25867 this.selectRow(i, true);
25873 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
25874 * @param {Number} startRow The index of the first row in the range
25875 * @param {Number} endRow The index of the last row in the range
25877 deselectRange : function(startRow, endRow, preventViewNotify){
25881 for(var i = startRow; i <= endRow; i++){
25882 this.deselectRow(i, preventViewNotify);
25888 * @param {Number} row The index of the row to select
25889 * @param {Boolean} keepExisting (optional) True to keep existing selections
25891 selectRow : function(index, keepExisting, preventViewNotify)
25893 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
25896 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
25897 if(!keepExisting || this.singleSelect){
25898 this.clearSelections();
25901 var r = this.grid.store.getAt(index);
25902 //console.log('selectRow - record id :' + r.id);
25904 this.selections.add(r);
25905 this.last = this.lastActive = index;
25906 if(!preventViewNotify){
25907 var proxy = new Roo.Element(
25908 this.grid.getRowDom(index)
25910 proxy.addClass('bg-info info');
25912 this.fireEvent("rowselect", this, index, r);
25913 this.fireEvent("selectionchange", this);
25919 * @param {Number} row The index of the row to deselect
25921 deselectRow : function(index, preventViewNotify)
25926 if(this.last == index){
25929 if(this.lastActive == index){
25930 this.lastActive = false;
25933 var r = this.grid.store.getAt(index);
25938 this.selections.remove(r);
25939 //.console.log('deselectRow - record id :' + r.id);
25940 if(!preventViewNotify){
25942 var proxy = new Roo.Element(
25943 this.grid.getRowDom(index)
25945 proxy.removeClass('bg-info info');
25947 this.fireEvent("rowdeselect", this, index);
25948 this.fireEvent("selectionchange", this);
25952 restoreLast : function(){
25954 this.last = this._last;
25959 acceptsNav : function(row, col, cm){
25960 return !cm.isHidden(col) && cm.isCellEditable(col, row);
25964 onEditorKey : function(field, e){
25965 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
25970 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
25972 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
25974 }else if(k == e.ENTER && !e.ctrlKey){
25978 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
25980 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
25982 }else if(k == e.ESC){
25986 g.startEditing(newCell[0], newCell[1]);
25992 * Ext JS Library 1.1.1
25993 * Copyright(c) 2006-2007, Ext JS, LLC.
25995 * Originally Released Under LGPL - original licence link has changed is not relivant.
25998 * <script type="text/javascript">
26002 * @class Roo.bootstrap.PagingToolbar
26003 * @extends Roo.bootstrap.NavSimplebar
26004 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26006 * Create a new PagingToolbar
26007 * @param {Object} config The config object
26008 * @param {Roo.data.Store} store
26010 Roo.bootstrap.PagingToolbar = function(config)
26012 // old args format still supported... - xtype is prefered..
26013 // created from xtype...
26015 this.ds = config.dataSource;
26017 if (config.store && !this.ds) {
26018 this.store= Roo.factory(config.store, Roo.data);
26019 this.ds = this.store;
26020 this.ds.xmodule = this.xmodule || false;
26023 this.toolbarItems = [];
26024 if (config.items) {
26025 this.toolbarItems = config.items;
26028 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
26033 this.bind(this.ds);
26036 if (Roo.bootstrap.version == 4) {
26037 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
26039 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
26044 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
26046 * @cfg {Roo.data.Store} dataSource
26047 * The underlying data store providing the paged data
26050 * @cfg {String/HTMLElement/Element} container
26051 * container The id or element that will contain the toolbar
26054 * @cfg {Boolean} displayInfo
26055 * True to display the displayMsg (defaults to false)
26058 * @cfg {Number} pageSize
26059 * The number of records to display per page (defaults to 20)
26063 * @cfg {String} displayMsg
26064 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26066 displayMsg : 'Displaying {0} - {1} of {2}',
26068 * @cfg {String} emptyMsg
26069 * The message to display when no records are found (defaults to "No data to display")
26071 emptyMsg : 'No data to display',
26073 * Customizable piece of the default paging text (defaults to "Page")
26076 beforePageText : "Page",
26078 * Customizable piece of the default paging text (defaults to "of %0")
26081 afterPageText : "of {0}",
26083 * Customizable piece of the default paging text (defaults to "First Page")
26086 firstText : "First Page",
26088 * Customizable piece of the default paging text (defaults to "Previous Page")
26091 prevText : "Previous Page",
26093 * Customizable piece of the default paging text (defaults to "Next Page")
26096 nextText : "Next Page",
26098 * Customizable piece of the default paging text (defaults to "Last Page")
26101 lastText : "Last Page",
26103 * Customizable piece of the default paging text (defaults to "Refresh")
26106 refreshText : "Refresh",
26110 onRender : function(ct, position)
26112 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
26113 this.navgroup.parentId = this.id;
26114 this.navgroup.onRender(this.el, null);
26115 // add the buttons to the navgroup
26117 if(this.displayInfo){
26118 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
26119 this.displayEl = this.el.select('.x-paging-info', true).first();
26120 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
26121 // this.displayEl = navel.el.select('span',true).first();
26127 Roo.each(_this.buttons, function(e){ // this might need to use render????
26128 Roo.factory(e).render(_this.el);
26132 Roo.each(_this.toolbarItems, function(e) {
26133 _this.navgroup.addItem(e);
26137 this.first = this.navgroup.addItem({
26138 tooltip: this.firstText,
26139 cls: "prev btn-outline-secondary",
26140 html : ' <i class="fa fa-step-backward"></i>',
26142 preventDefault: true,
26143 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
26146 this.prev = this.navgroup.addItem({
26147 tooltip: this.prevText,
26148 cls: "prev btn-outline-secondary",
26149 html : ' <i class="fa fa-backward"></i>',
26151 preventDefault: true,
26152 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
26154 //this.addSeparator();
26157 var field = this.navgroup.addItem( {
26159 cls : 'x-paging-position btn-outline-secondary',
26161 html : this.beforePageText +
26162 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
26163 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
26166 this.field = field.el.select('input', true).first();
26167 this.field.on("keydown", this.onPagingKeydown, this);
26168 this.field.on("focus", function(){this.dom.select();});
26171 this.afterTextEl = field.el.select('.x-paging-after',true).first();
26172 //this.field.setHeight(18);
26173 //this.addSeparator();
26174 this.next = this.navgroup.addItem({
26175 tooltip: this.nextText,
26176 cls: "next btn-outline-secondary",
26177 html : ' <i class="fa fa-forward"></i>',
26179 preventDefault: true,
26180 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
26182 this.last = this.navgroup.addItem({
26183 tooltip: this.lastText,
26184 html : ' <i class="fa fa-step-forward"></i>',
26185 cls: "next btn-outline-secondary",
26187 preventDefault: true,
26188 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
26190 //this.addSeparator();
26191 this.loading = this.navgroup.addItem({
26192 tooltip: this.refreshText,
26193 cls: "btn-outline-secondary",
26194 html : ' <i class="fa fa-refresh"></i>',
26195 preventDefault: true,
26196 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
26202 updateInfo : function(){
26203 if(this.displayEl){
26204 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
26205 var msg = count == 0 ?
26209 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
26211 this.displayEl.update(msg);
26216 onLoad : function(ds, r, o)
26218 this.cursor = o.params.start ? o.params.start : 0;
26220 var d = this.getPageData(),
26225 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
26226 this.field.dom.value = ap;
26227 this.first.setDisabled(ap == 1);
26228 this.prev.setDisabled(ap == 1);
26229 this.next.setDisabled(ap == ps);
26230 this.last.setDisabled(ap == ps);
26231 this.loading.enable();
26236 getPageData : function(){
26237 var total = this.ds.getTotalCount();
26240 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
26241 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
26246 onLoadError : function(){
26247 this.loading.enable();
26251 onPagingKeydown : function(e){
26252 var k = e.getKey();
26253 var d = this.getPageData();
26255 var v = this.field.dom.value, pageNum;
26256 if(!v || isNaN(pageNum = parseInt(v, 10))){
26257 this.field.dom.value = d.activePage;
26260 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
26261 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
26264 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))
26266 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
26267 this.field.dom.value = pageNum;
26268 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
26271 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
26273 var v = this.field.dom.value, pageNum;
26274 var increment = (e.shiftKey) ? 10 : 1;
26275 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
26278 if(!v || isNaN(pageNum = parseInt(v, 10))) {
26279 this.field.dom.value = d.activePage;
26282 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
26284 this.field.dom.value = parseInt(v, 10) + increment;
26285 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
26286 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
26293 beforeLoad : function(){
26295 this.loading.disable();
26300 onClick : function(which){
26309 ds.load({params:{start: 0, limit: this.pageSize}});
26312 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
26315 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
26318 var total = ds.getTotalCount();
26319 var extra = total % this.pageSize;
26320 var lastStart = extra ? (total - extra) : total-this.pageSize;
26321 ds.load({params:{start: lastStart, limit: this.pageSize}});
26324 ds.load({params:{start: this.cursor, limit: this.pageSize}});
26330 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
26331 * @param {Roo.data.Store} store The data store to unbind
26333 unbind : function(ds){
26334 ds.un("beforeload", this.beforeLoad, this);
26335 ds.un("load", this.onLoad, this);
26336 ds.un("loadexception", this.onLoadError, this);
26337 ds.un("remove", this.updateInfo, this);
26338 ds.un("add", this.updateInfo, this);
26339 this.ds = undefined;
26343 * Binds the paging toolbar to the specified {@link Roo.data.Store}
26344 * @param {Roo.data.Store} store The data store to bind
26346 bind : function(ds){
26347 ds.on("beforeload", this.beforeLoad, this);
26348 ds.on("load", this.onLoad, this);
26349 ds.on("loadexception", this.onLoadError, this);
26350 ds.on("remove", this.updateInfo, this);
26351 ds.on("add", this.updateInfo, this);
26362 * @class Roo.bootstrap.MessageBar
26363 * @extends Roo.bootstrap.Component
26364 * Bootstrap MessageBar class
26365 * @cfg {String} html contents of the MessageBar
26366 * @cfg {String} weight (info | success | warning | danger) default info
26367 * @cfg {String} beforeClass insert the bar before the given class
26368 * @cfg {Boolean} closable (true | false) default false
26369 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
26372 * Create a new Element
26373 * @param {Object} config The config object
26376 Roo.bootstrap.MessageBar = function(config){
26377 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
26380 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
26386 beforeClass: 'bootstrap-sticky-wrap',
26388 getAutoCreate : function(){
26392 cls: 'alert alert-dismissable alert-' + this.weight,
26397 html: this.html || ''
26403 cfg.cls += ' alert-messages-fixed';
26417 onRender : function(ct, position)
26419 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
26422 var cfg = Roo.apply({}, this.getAutoCreate());
26426 cfg.cls += ' ' + this.cls;
26429 cfg.style = this.style;
26431 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
26433 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26436 this.el.select('>button.close').on('click', this.hide, this);
26442 if (!this.rendered) {
26448 this.fireEvent('show', this);
26454 if (!this.rendered) {
26460 this.fireEvent('hide', this);
26463 update : function()
26465 // var e = this.el.dom.firstChild;
26467 // if(this.closable){
26468 // e = e.nextSibling;
26471 // e.data = this.html || '';
26473 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
26489 * @class Roo.bootstrap.Graph
26490 * @extends Roo.bootstrap.Component
26491 * Bootstrap Graph class
26495 @cfg {String} graphtype bar | vbar | pie
26496 @cfg {number} g_x coodinator | centre x (pie)
26497 @cfg {number} g_y coodinator | centre y (pie)
26498 @cfg {number} g_r radius (pie)
26499 @cfg {number} g_height height of the chart (respected by all elements in the set)
26500 @cfg {number} g_width width of the chart (respected by all elements in the set)
26501 @cfg {Object} title The title of the chart
26504 -opts (object) options for the chart
26506 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
26507 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
26509 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.
26510 o stacked (boolean) whether or not to tread values as in a stacked bar chart
26512 o stretch (boolean)
26514 -opts (object) options for the pie
26517 o startAngle (number)
26518 o endAngle (number)
26522 * Create a new Input
26523 * @param {Object} config The config object
26526 Roo.bootstrap.Graph = function(config){
26527 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
26533 * The img click event for the img.
26534 * @param {Roo.EventObject} e
26540 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
26551 //g_colors: this.colors,
26558 getAutoCreate : function(){
26569 onRender : function(ct,position){
26572 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
26574 if (typeof(Raphael) == 'undefined') {
26575 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
26579 this.raphael = Raphael(this.el.dom);
26581 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26582 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26583 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26584 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
26586 r.text(160, 10, "Single Series Chart").attr(txtattr);
26587 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
26588 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
26589 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
26591 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
26592 r.barchart(330, 10, 300, 220, data1);
26593 r.barchart(10, 250, 300, 220, data2, {stacked: true});
26594 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
26597 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
26598 // r.barchart(30, 30, 560, 250, xdata, {
26599 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
26600 // axis : "0 0 1 1",
26601 // axisxlabels : xdata
26602 // //yvalues : cols,
26605 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
26607 // this.load(null,xdata,{
26608 // axis : "0 0 1 1",
26609 // axisxlabels : xdata
26614 load : function(graphtype,xdata,opts)
26616 this.raphael.clear();
26618 graphtype = this.graphtype;
26623 var r = this.raphael,
26624 fin = function () {
26625 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
26627 fout = function () {
26628 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
26630 pfin = function() {
26631 this.sector.stop();
26632 this.sector.scale(1.1, 1.1, this.cx, this.cy);
26635 this.label[0].stop();
26636 this.label[0].attr({ r: 7.5 });
26637 this.label[1].attr({ "font-weight": 800 });
26640 pfout = function() {
26641 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
26644 this.label[0].animate({ r: 5 }, 500, "bounce");
26645 this.label[1].attr({ "font-weight": 400 });
26651 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
26654 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
26657 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
26658 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
26660 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
26667 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
26672 setTitle: function(o)
26677 initEvents: function() {
26680 this.el.on('click', this.onClick, this);
26684 onClick : function(e)
26686 Roo.log('img onclick');
26687 this.fireEvent('click', this, e);
26699 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26702 * @class Roo.bootstrap.dash.NumberBox
26703 * @extends Roo.bootstrap.Component
26704 * Bootstrap NumberBox class
26705 * @cfg {String} headline Box headline
26706 * @cfg {String} content Box content
26707 * @cfg {String} icon Box icon
26708 * @cfg {String} footer Footer text
26709 * @cfg {String} fhref Footer href
26712 * Create a new NumberBox
26713 * @param {Object} config The config object
26717 Roo.bootstrap.dash.NumberBox = function(config){
26718 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
26722 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
26731 getAutoCreate : function(){
26735 cls : 'small-box ',
26743 cls : 'roo-headline',
26744 html : this.headline
26748 cls : 'roo-content',
26749 html : this.content
26763 cls : 'ion ' + this.icon
26772 cls : 'small-box-footer',
26773 href : this.fhref || '#',
26777 cfg.cn.push(footer);
26784 onRender : function(ct,position){
26785 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
26792 setHeadline: function (value)
26794 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
26797 setFooter: function (value, href)
26799 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
26802 this.el.select('a.small-box-footer',true).first().attr('href', href);
26807 setContent: function (value)
26809 this.el.select('.roo-content',true).first().dom.innerHTML = value;
26812 initEvents: function()
26826 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26829 * @class Roo.bootstrap.dash.TabBox
26830 * @extends Roo.bootstrap.Component
26831 * Bootstrap TabBox class
26832 * @cfg {String} title Title of the TabBox
26833 * @cfg {String} icon Icon of the TabBox
26834 * @cfg {Boolean} showtabs (true|false) show the tabs default true
26835 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
26838 * Create a new TabBox
26839 * @param {Object} config The config object
26843 Roo.bootstrap.dash.TabBox = function(config){
26844 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
26849 * When a pane is added
26850 * @param {Roo.bootstrap.dash.TabPane} pane
26854 * @event activatepane
26855 * When a pane is activated
26856 * @param {Roo.bootstrap.dash.TabPane} pane
26858 "activatepane" : true
26866 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
26871 tabScrollable : false,
26873 getChildContainer : function()
26875 return this.el.select('.tab-content', true).first();
26878 getAutoCreate : function(){
26882 cls: 'pull-left header',
26890 cls: 'fa ' + this.icon
26896 cls: 'nav nav-tabs pull-right',
26902 if(this.tabScrollable){
26909 cls: 'nav nav-tabs pull-right',
26920 cls: 'nav-tabs-custom',
26925 cls: 'tab-content no-padding',
26933 initEvents : function()
26935 //Roo.log('add add pane handler');
26936 this.on('addpane', this.onAddPane, this);
26939 * Updates the box title
26940 * @param {String} html to set the title to.
26942 setTitle : function(value)
26944 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
26946 onAddPane : function(pane)
26948 this.panes.push(pane);
26949 //Roo.log('addpane');
26951 // tabs are rendere left to right..
26952 if(!this.showtabs){
26956 var ctr = this.el.select('.nav-tabs', true).first();
26959 var existing = ctr.select('.nav-tab',true);
26960 var qty = existing.getCount();;
26963 var tab = ctr.createChild({
26965 cls : 'nav-tab' + (qty ? '' : ' active'),
26973 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
26976 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
26978 pane.el.addClass('active');
26983 onTabClick : function(ev,un,ob,pane)
26985 //Roo.log('tab - prev default');
26986 ev.preventDefault();
26989 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
26990 pane.tab.addClass('active');
26991 //Roo.log(pane.title);
26992 this.getChildContainer().select('.tab-pane',true).removeClass('active');
26993 // technically we should have a deactivate event.. but maybe add later.
26994 // and it should not de-activate the selected tab...
26995 this.fireEvent('activatepane', pane);
26996 pane.el.addClass('active');
26997 pane.fireEvent('activate');
27002 getActivePane : function()
27005 Roo.each(this.panes, function(p) {
27006 if(p.el.hasClass('active')){
27027 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27029 * @class Roo.bootstrap.TabPane
27030 * @extends Roo.bootstrap.Component
27031 * Bootstrap TabPane class
27032 * @cfg {Boolean} active (false | true) Default false
27033 * @cfg {String} title title of panel
27037 * Create a new TabPane
27038 * @param {Object} config The config object
27041 Roo.bootstrap.dash.TabPane = function(config){
27042 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
27048 * When a pane is activated
27049 * @param {Roo.bootstrap.dash.TabPane} pane
27056 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
27061 // the tabBox that this is attached to.
27064 getAutoCreate : function()
27072 cfg.cls += ' active';
27077 initEvents : function()
27079 //Roo.log('trigger add pane handler');
27080 this.parent().fireEvent('addpane', this)
27084 * Updates the tab title
27085 * @param {String} html to set the title to.
27087 setTitle: function(str)
27093 this.tab.select('a', true).first().dom.innerHTML = str;
27110 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27113 * @class Roo.bootstrap.menu.Menu
27114 * @extends Roo.bootstrap.Component
27115 * Bootstrap Menu class - container for Menu
27116 * @cfg {String} html Text of the menu
27117 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
27118 * @cfg {String} icon Font awesome icon
27119 * @cfg {String} pos Menu align to (top | bottom) default bottom
27123 * Create a new Menu
27124 * @param {Object} config The config object
27128 Roo.bootstrap.menu.Menu = function(config){
27129 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
27133 * @event beforeshow
27134 * Fires before this menu is displayed
27135 * @param {Roo.bootstrap.menu.Menu} this
27139 * @event beforehide
27140 * Fires before this menu is hidden
27141 * @param {Roo.bootstrap.menu.Menu} this
27146 * Fires after this menu is displayed
27147 * @param {Roo.bootstrap.menu.Menu} this
27152 * Fires after this menu is hidden
27153 * @param {Roo.bootstrap.menu.Menu} this
27158 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
27159 * @param {Roo.bootstrap.menu.Menu} this
27160 * @param {Roo.EventObject} e
27167 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
27171 weight : 'default',
27176 getChildContainer : function() {
27177 if(this.isSubMenu){
27181 return this.el.select('ul.dropdown-menu', true).first();
27184 getAutoCreate : function()
27189 cls : 'roo-menu-text',
27197 cls : 'fa ' + this.icon
27208 cls : 'dropdown-button btn btn-' + this.weight,
27213 cls : 'dropdown-toggle btn btn-' + this.weight,
27223 cls : 'dropdown-menu'
27229 if(this.pos == 'top'){
27230 cfg.cls += ' dropup';
27233 if(this.isSubMenu){
27236 cls : 'dropdown-menu'
27243 onRender : function(ct, position)
27245 this.isSubMenu = ct.hasClass('dropdown-submenu');
27247 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
27250 initEvents : function()
27252 if(this.isSubMenu){
27256 this.hidden = true;
27258 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
27259 this.triggerEl.on('click', this.onTriggerPress, this);
27261 this.buttonEl = this.el.select('button.dropdown-button', true).first();
27262 this.buttonEl.on('click', this.onClick, this);
27268 if(this.isSubMenu){
27272 return this.el.select('ul.dropdown-menu', true).first();
27275 onClick : function(e)
27277 this.fireEvent("click", this, e);
27280 onTriggerPress : function(e)
27282 if (this.isVisible()) {
27289 isVisible : function(){
27290 return !this.hidden;
27295 this.fireEvent("beforeshow", this);
27297 this.hidden = false;
27298 this.el.addClass('open');
27300 Roo.get(document).on("mouseup", this.onMouseUp, this);
27302 this.fireEvent("show", this);
27309 this.fireEvent("beforehide", this);
27311 this.hidden = true;
27312 this.el.removeClass('open');
27314 Roo.get(document).un("mouseup", this.onMouseUp);
27316 this.fireEvent("hide", this);
27319 onMouseUp : function()
27333 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27336 * @class Roo.bootstrap.menu.Item
27337 * @extends Roo.bootstrap.Component
27338 * Bootstrap MenuItem class
27339 * @cfg {Boolean} submenu (true | false) default false
27340 * @cfg {String} html text of the item
27341 * @cfg {String} href the link
27342 * @cfg {Boolean} disable (true | false) default false
27343 * @cfg {Boolean} preventDefault (true | false) default true
27344 * @cfg {String} icon Font awesome icon
27345 * @cfg {String} pos Submenu align to (left | right) default right
27349 * Create a new Item
27350 * @param {Object} config The config object
27354 Roo.bootstrap.menu.Item = function(config){
27355 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
27359 * Fires when the mouse is hovering over this menu
27360 * @param {Roo.bootstrap.menu.Item} this
27361 * @param {Roo.EventObject} e
27366 * Fires when the mouse exits this menu
27367 * @param {Roo.bootstrap.menu.Item} this
27368 * @param {Roo.EventObject} e
27374 * The raw click event for the entire grid.
27375 * @param {Roo.EventObject} e
27381 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
27386 preventDefault: true,
27391 getAutoCreate : function()
27396 cls : 'roo-menu-item-text',
27404 cls : 'fa ' + this.icon
27413 href : this.href || '#',
27420 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
27424 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
27426 if(this.pos == 'left'){
27427 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
27434 initEvents : function()
27436 this.el.on('mouseover', this.onMouseOver, this);
27437 this.el.on('mouseout', this.onMouseOut, this);
27439 this.el.select('a', true).first().on('click', this.onClick, this);
27443 onClick : function(e)
27445 if(this.preventDefault){
27446 e.preventDefault();
27449 this.fireEvent("click", this, e);
27452 onMouseOver : function(e)
27454 if(this.submenu && this.pos == 'left'){
27455 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
27458 this.fireEvent("mouseover", this, e);
27461 onMouseOut : function(e)
27463 this.fireEvent("mouseout", this, e);
27475 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27478 * @class Roo.bootstrap.menu.Separator
27479 * @extends Roo.bootstrap.Component
27480 * Bootstrap Separator class
27483 * Create a new Separator
27484 * @param {Object} config The config object
27488 Roo.bootstrap.menu.Separator = function(config){
27489 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
27492 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
27494 getAutoCreate : function(){
27515 * @class Roo.bootstrap.Tooltip
27516 * Bootstrap Tooltip class
27517 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
27518 * to determine which dom element triggers the tooltip.
27520 * It needs to add support for additional attributes like tooltip-position
27523 * Create a new Toolti
27524 * @param {Object} config The config object
27527 Roo.bootstrap.Tooltip = function(config){
27528 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
27530 this.alignment = Roo.bootstrap.Tooltip.alignment;
27532 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
27533 this.alignment = config.alignment;
27538 Roo.apply(Roo.bootstrap.Tooltip, {
27540 * @function init initialize tooltip monitoring.
27544 currentTip : false,
27545 currentRegion : false,
27551 Roo.get(document).on('mouseover', this.enter ,this);
27552 Roo.get(document).on('mouseout', this.leave, this);
27555 this.currentTip = new Roo.bootstrap.Tooltip();
27558 enter : function(ev)
27560 var dom = ev.getTarget();
27562 //Roo.log(['enter',dom]);
27563 var el = Roo.fly(dom);
27564 if (this.currentEl) {
27566 //Roo.log(this.currentEl);
27567 //Roo.log(this.currentEl.contains(dom));
27568 if (this.currentEl == el) {
27571 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
27577 if (this.currentTip.el) {
27578 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
27582 if(!el || el.dom == document){
27588 // you can not look for children, as if el is the body.. then everythign is the child..
27589 if (!el.attr('tooltip')) { //
27590 if (!el.select("[tooltip]").elements.length) {
27593 // is the mouse over this child...?
27594 bindEl = el.select("[tooltip]").first();
27595 var xy = ev.getXY();
27596 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
27597 //Roo.log("not in region.");
27600 //Roo.log("child element over..");
27603 this.currentEl = bindEl;
27604 this.currentTip.bind(bindEl);
27605 this.currentRegion = Roo.lib.Region.getRegion(dom);
27606 this.currentTip.enter();
27609 leave : function(ev)
27611 var dom = ev.getTarget();
27612 //Roo.log(['leave',dom]);
27613 if (!this.currentEl) {
27618 if (dom != this.currentEl.dom) {
27621 var xy = ev.getXY();
27622 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
27625 // only activate leave if mouse cursor is outside... bounding box..
27630 if (this.currentTip) {
27631 this.currentTip.leave();
27633 //Roo.log('clear currentEl');
27634 this.currentEl = false;
27639 'left' : ['r-l', [-2,0], 'right'],
27640 'right' : ['l-r', [2,0], 'left'],
27641 'bottom' : ['t-b', [0,2], 'top'],
27642 'top' : [ 'b-t', [0,-2], 'bottom']
27648 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
27653 delay : null, // can be { show : 300 , hide: 500}
27657 hoverState : null, //???
27659 placement : 'bottom',
27663 getAutoCreate : function(){
27670 cls : 'tooltip-arrow'
27673 cls : 'tooltip-inner'
27680 bind : function(el)
27686 enter : function () {
27688 if (this.timeout != null) {
27689 clearTimeout(this.timeout);
27692 this.hoverState = 'in';
27693 //Roo.log("enter - show");
27694 if (!this.delay || !this.delay.show) {
27699 this.timeout = setTimeout(function () {
27700 if (_t.hoverState == 'in') {
27703 }, this.delay.show);
27707 clearTimeout(this.timeout);
27709 this.hoverState = 'out';
27710 if (!this.delay || !this.delay.hide) {
27716 this.timeout = setTimeout(function () {
27717 //Roo.log("leave - timeout");
27719 if (_t.hoverState == 'out') {
27721 Roo.bootstrap.Tooltip.currentEl = false;
27726 show : function (msg)
27729 this.render(document.body);
27732 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
27734 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
27736 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
27738 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
27740 var placement = typeof this.placement == 'function' ?
27741 this.placement.call(this, this.el, on_el) :
27744 var autoToken = /\s?auto?\s?/i;
27745 var autoPlace = autoToken.test(placement);
27747 placement = placement.replace(autoToken, '') || 'top';
27751 //this.el.setXY([0,0]);
27753 //this.el.dom.style.display='block';
27755 //this.el.appendTo(on_el);
27757 var p = this.getPosition();
27758 var box = this.el.getBox();
27764 var align = this.alignment[placement];
27766 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
27768 if(placement == 'top' || placement == 'bottom'){
27770 placement = 'right';
27773 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
27774 placement = 'left';
27777 var scroll = Roo.select('body', true).first().getScroll();
27779 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
27783 align = this.alignment[placement];
27786 this.el.alignTo(this.bindEl, align[0],align[1]);
27787 //var arrow = this.el.select('.arrow',true).first();
27788 //arrow.set(align[2],
27790 this.el.addClass(placement);
27792 this.el.addClass('in fade');
27794 this.hoverState = null;
27796 if (this.el.hasClass('fade')) {
27807 //this.el.setXY([0,0]);
27808 this.el.removeClass('in');
27824 * @class Roo.bootstrap.LocationPicker
27825 * @extends Roo.bootstrap.Component
27826 * Bootstrap LocationPicker class
27827 * @cfg {Number} latitude Position when init default 0
27828 * @cfg {Number} longitude Position when init default 0
27829 * @cfg {Number} zoom default 15
27830 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
27831 * @cfg {Boolean} mapTypeControl default false
27832 * @cfg {Boolean} disableDoubleClickZoom default false
27833 * @cfg {Boolean} scrollwheel default true
27834 * @cfg {Boolean} streetViewControl default false
27835 * @cfg {Number} radius default 0
27836 * @cfg {String} locationName
27837 * @cfg {Boolean} draggable default true
27838 * @cfg {Boolean} enableAutocomplete default false
27839 * @cfg {Boolean} enableReverseGeocode default true
27840 * @cfg {String} markerTitle
27843 * Create a new LocationPicker
27844 * @param {Object} config The config object
27848 Roo.bootstrap.LocationPicker = function(config){
27850 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
27855 * Fires when the picker initialized.
27856 * @param {Roo.bootstrap.LocationPicker} this
27857 * @param {Google Location} location
27861 * @event positionchanged
27862 * Fires when the picker position changed.
27863 * @param {Roo.bootstrap.LocationPicker} this
27864 * @param {Google Location} location
27866 positionchanged : true,
27869 * Fires when the map resize.
27870 * @param {Roo.bootstrap.LocationPicker} this
27875 * Fires when the map show.
27876 * @param {Roo.bootstrap.LocationPicker} this
27881 * Fires when the map hide.
27882 * @param {Roo.bootstrap.LocationPicker} this
27887 * Fires when click the map.
27888 * @param {Roo.bootstrap.LocationPicker} this
27889 * @param {Map event} e
27893 * @event mapRightClick
27894 * Fires when right click the map.
27895 * @param {Roo.bootstrap.LocationPicker} this
27896 * @param {Map event} e
27898 mapRightClick : true,
27900 * @event markerClick
27901 * Fires when click the marker.
27902 * @param {Roo.bootstrap.LocationPicker} this
27903 * @param {Map event} e
27905 markerClick : true,
27907 * @event markerRightClick
27908 * Fires when right click the marker.
27909 * @param {Roo.bootstrap.LocationPicker} this
27910 * @param {Map event} e
27912 markerRightClick : true,
27914 * @event OverlayViewDraw
27915 * Fires when OverlayView Draw
27916 * @param {Roo.bootstrap.LocationPicker} this
27918 OverlayViewDraw : true,
27920 * @event OverlayViewOnAdd
27921 * Fires when OverlayView Draw
27922 * @param {Roo.bootstrap.LocationPicker} this
27924 OverlayViewOnAdd : true,
27926 * @event OverlayViewOnRemove
27927 * Fires when OverlayView Draw
27928 * @param {Roo.bootstrap.LocationPicker} this
27930 OverlayViewOnRemove : true,
27932 * @event OverlayViewShow
27933 * Fires when OverlayView Draw
27934 * @param {Roo.bootstrap.LocationPicker} this
27935 * @param {Pixel} cpx
27937 OverlayViewShow : true,
27939 * @event OverlayViewHide
27940 * Fires when OverlayView Draw
27941 * @param {Roo.bootstrap.LocationPicker} this
27943 OverlayViewHide : true,
27945 * @event loadexception
27946 * Fires when load google lib failed.
27947 * @param {Roo.bootstrap.LocationPicker} this
27949 loadexception : true
27954 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
27956 gMapContext: false,
27962 mapTypeControl: false,
27963 disableDoubleClickZoom: false,
27965 streetViewControl: false,
27969 enableAutocomplete: false,
27970 enableReverseGeocode: true,
27973 getAutoCreate: function()
27978 cls: 'roo-location-picker'
27984 initEvents: function(ct, position)
27986 if(!this.el.getWidth() || this.isApplied()){
27990 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27995 initial: function()
27997 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
27998 this.fireEvent('loadexception', this);
28002 if(!this.mapTypeId){
28003 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
28006 this.gMapContext = this.GMapContext();
28008 this.initOverlayView();
28010 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
28014 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
28015 _this.setPosition(_this.gMapContext.marker.position);
28018 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
28019 _this.fireEvent('mapClick', this, event);
28023 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
28024 _this.fireEvent('mapRightClick', this, event);
28028 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
28029 _this.fireEvent('markerClick', this, event);
28033 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
28034 _this.fireEvent('markerRightClick', this, event);
28038 this.setPosition(this.gMapContext.location);
28040 this.fireEvent('initial', this, this.gMapContext.location);
28043 initOverlayView: function()
28047 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
28051 _this.fireEvent('OverlayViewDraw', _this);
28056 _this.fireEvent('OverlayViewOnAdd', _this);
28059 onRemove: function()
28061 _this.fireEvent('OverlayViewOnRemove', _this);
28064 show: function(cpx)
28066 _this.fireEvent('OverlayViewShow', _this, cpx);
28071 _this.fireEvent('OverlayViewHide', _this);
28077 fromLatLngToContainerPixel: function(event)
28079 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
28082 isApplied: function()
28084 return this.getGmapContext() == false ? false : true;
28087 getGmapContext: function()
28089 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
28092 GMapContext: function()
28094 var position = new google.maps.LatLng(this.latitude, this.longitude);
28096 var _map = new google.maps.Map(this.el.dom, {
28099 mapTypeId: this.mapTypeId,
28100 mapTypeControl: this.mapTypeControl,
28101 disableDoubleClickZoom: this.disableDoubleClickZoom,
28102 scrollwheel: this.scrollwheel,
28103 streetViewControl: this.streetViewControl,
28104 locationName: this.locationName,
28105 draggable: this.draggable,
28106 enableAutocomplete: this.enableAutocomplete,
28107 enableReverseGeocode: this.enableReverseGeocode
28110 var _marker = new google.maps.Marker({
28111 position: position,
28113 title: this.markerTitle,
28114 draggable: this.draggable
28121 location: position,
28122 radius: this.radius,
28123 locationName: this.locationName,
28124 addressComponents: {
28125 formatted_address: null,
28126 addressLine1: null,
28127 addressLine2: null,
28129 streetNumber: null,
28133 stateOrProvince: null
28136 domContainer: this.el.dom,
28137 geodecoder: new google.maps.Geocoder()
28141 drawCircle: function(center, radius, options)
28143 if (this.gMapContext.circle != null) {
28144 this.gMapContext.circle.setMap(null);
28148 options = Roo.apply({}, options, {
28149 strokeColor: "#0000FF",
28150 strokeOpacity: .35,
28152 fillColor: "#0000FF",
28156 options.map = this.gMapContext.map;
28157 options.radius = radius;
28158 options.center = center;
28159 this.gMapContext.circle = new google.maps.Circle(options);
28160 return this.gMapContext.circle;
28166 setPosition: function(location)
28168 this.gMapContext.location = location;
28169 this.gMapContext.marker.setPosition(location);
28170 this.gMapContext.map.panTo(location);
28171 this.drawCircle(location, this.gMapContext.radius, {});
28175 if (this.gMapContext.settings.enableReverseGeocode) {
28176 this.gMapContext.geodecoder.geocode({
28177 latLng: this.gMapContext.location
28178 }, function(results, status) {
28180 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
28181 _this.gMapContext.locationName = results[0].formatted_address;
28182 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
28184 _this.fireEvent('positionchanged', this, location);
28191 this.fireEvent('positionchanged', this, location);
28196 google.maps.event.trigger(this.gMapContext.map, "resize");
28198 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
28200 this.fireEvent('resize', this);
28203 setPositionByLatLng: function(latitude, longitude)
28205 this.setPosition(new google.maps.LatLng(latitude, longitude));
28208 getCurrentPosition: function()
28211 latitude: this.gMapContext.location.lat(),
28212 longitude: this.gMapContext.location.lng()
28216 getAddressName: function()
28218 return this.gMapContext.locationName;
28221 getAddressComponents: function()
28223 return this.gMapContext.addressComponents;
28226 address_component_from_google_geocode: function(address_components)
28230 for (var i = 0; i < address_components.length; i++) {
28231 var component = address_components[i];
28232 if (component.types.indexOf("postal_code") >= 0) {
28233 result.postalCode = component.short_name;
28234 } else if (component.types.indexOf("street_number") >= 0) {
28235 result.streetNumber = component.short_name;
28236 } else if (component.types.indexOf("route") >= 0) {
28237 result.streetName = component.short_name;
28238 } else if (component.types.indexOf("neighborhood") >= 0) {
28239 result.city = component.short_name;
28240 } else if (component.types.indexOf("locality") >= 0) {
28241 result.city = component.short_name;
28242 } else if (component.types.indexOf("sublocality") >= 0) {
28243 result.district = component.short_name;
28244 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
28245 result.stateOrProvince = component.short_name;
28246 } else if (component.types.indexOf("country") >= 0) {
28247 result.country = component.short_name;
28251 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
28252 result.addressLine2 = "";
28256 setZoomLevel: function(zoom)
28258 this.gMapContext.map.setZoom(zoom);
28271 this.fireEvent('show', this);
28282 this.fireEvent('hide', this);
28287 Roo.apply(Roo.bootstrap.LocationPicker, {
28289 OverlayView : function(map, options)
28291 options = options || {};
28298 * @class Roo.bootstrap.Alert
28299 * @extends Roo.bootstrap.Component
28300 * Bootstrap Alert class - shows an alert area box
28302 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
28303 Enter a valid email address
28306 * @cfg {String} title The title of alert
28307 * @cfg {String} html The content of alert
28308 * @cfg {String} weight ( success | info | warning | danger )
28309 * @cfg {String} faicon font-awesomeicon
28312 * Create a new alert
28313 * @param {Object} config The config object
28317 Roo.bootstrap.Alert = function(config){
28318 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
28322 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
28329 getAutoCreate : function()
28338 cls : 'roo-alert-icon'
28343 cls : 'roo-alert-title',
28348 cls : 'roo-alert-text',
28355 cfg.cn[0].cls += ' fa ' + this.faicon;
28359 cfg.cls += ' alert-' + this.weight;
28365 initEvents: function()
28367 this.el.setVisibilityMode(Roo.Element.DISPLAY);
28370 setTitle : function(str)
28372 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
28375 setText : function(str)
28377 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
28380 setWeight : function(weight)
28383 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
28386 this.weight = weight;
28388 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
28391 setIcon : function(icon)
28394 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
28397 this.faicon = icon;
28399 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
28420 * @class Roo.bootstrap.UploadCropbox
28421 * @extends Roo.bootstrap.Component
28422 * Bootstrap UploadCropbox class
28423 * @cfg {String} emptyText show when image has been loaded
28424 * @cfg {String} rotateNotify show when image too small to rotate
28425 * @cfg {Number} errorTimeout default 3000
28426 * @cfg {Number} minWidth default 300
28427 * @cfg {Number} minHeight default 300
28428 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
28429 * @cfg {Boolean} isDocument (true|false) default false
28430 * @cfg {String} url action url
28431 * @cfg {String} paramName default 'imageUpload'
28432 * @cfg {String} method default POST
28433 * @cfg {Boolean} loadMask (true|false) default true
28434 * @cfg {Boolean} loadingText default 'Loading...'
28437 * Create a new UploadCropbox
28438 * @param {Object} config The config object
28441 Roo.bootstrap.UploadCropbox = function(config){
28442 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
28446 * @event beforeselectfile
28447 * Fire before select file
28448 * @param {Roo.bootstrap.UploadCropbox} this
28450 "beforeselectfile" : true,
28453 * Fire after initEvent
28454 * @param {Roo.bootstrap.UploadCropbox} this
28459 * Fire after initEvent
28460 * @param {Roo.bootstrap.UploadCropbox} this
28461 * @param {String} data
28466 * Fire when preparing the file data
28467 * @param {Roo.bootstrap.UploadCropbox} this
28468 * @param {Object} file
28473 * Fire when get exception
28474 * @param {Roo.bootstrap.UploadCropbox} this
28475 * @param {XMLHttpRequest} xhr
28477 "exception" : true,
28479 * @event beforeloadcanvas
28480 * Fire before load the canvas
28481 * @param {Roo.bootstrap.UploadCropbox} this
28482 * @param {String} src
28484 "beforeloadcanvas" : true,
28487 * Fire when trash image
28488 * @param {Roo.bootstrap.UploadCropbox} this
28493 * Fire when download the image
28494 * @param {Roo.bootstrap.UploadCropbox} this
28498 * @event footerbuttonclick
28499 * Fire when footerbuttonclick
28500 * @param {Roo.bootstrap.UploadCropbox} this
28501 * @param {String} type
28503 "footerbuttonclick" : true,
28507 * @param {Roo.bootstrap.UploadCropbox} this
28512 * Fire when rotate the image
28513 * @param {Roo.bootstrap.UploadCropbox} this
28514 * @param {String} pos
28519 * Fire when inspect the file
28520 * @param {Roo.bootstrap.UploadCropbox} this
28521 * @param {Object} file
28526 * Fire when xhr upload the file
28527 * @param {Roo.bootstrap.UploadCropbox} this
28528 * @param {Object} data
28533 * Fire when arrange the file data
28534 * @param {Roo.bootstrap.UploadCropbox} this
28535 * @param {Object} formData
28540 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
28543 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
28545 emptyText : 'Click to upload image',
28546 rotateNotify : 'Image is too small to rotate',
28547 errorTimeout : 3000,
28561 cropType : 'image/jpeg',
28563 canvasLoaded : false,
28564 isDocument : false,
28566 paramName : 'imageUpload',
28568 loadingText : 'Loading...',
28571 getAutoCreate : function()
28575 cls : 'roo-upload-cropbox',
28579 cls : 'roo-upload-cropbox-selector',
28584 cls : 'roo-upload-cropbox-body',
28585 style : 'cursor:pointer',
28589 cls : 'roo-upload-cropbox-preview'
28593 cls : 'roo-upload-cropbox-thumb'
28597 cls : 'roo-upload-cropbox-empty-notify',
28598 html : this.emptyText
28602 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
28603 html : this.rotateNotify
28609 cls : 'roo-upload-cropbox-footer',
28612 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
28622 onRender : function(ct, position)
28624 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
28626 if (this.buttons.length) {
28628 Roo.each(this.buttons, function(bb) {
28630 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
28632 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
28638 this.maskEl = this.el;
28642 initEvents : function()
28644 this.urlAPI = (window.createObjectURL && window) ||
28645 (window.URL && URL.revokeObjectURL && URL) ||
28646 (window.webkitURL && webkitURL);
28648 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
28649 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28651 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
28652 this.selectorEl.hide();
28654 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
28655 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28657 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
28658 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28659 this.thumbEl.hide();
28661 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
28662 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28664 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
28665 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28666 this.errorEl.hide();
28668 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
28669 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28670 this.footerEl.hide();
28672 this.setThumbBoxSize();
28678 this.fireEvent('initial', this);
28685 window.addEventListener("resize", function() { _this.resize(); } );
28687 this.bodyEl.on('click', this.beforeSelectFile, this);
28690 this.bodyEl.on('touchstart', this.onTouchStart, this);
28691 this.bodyEl.on('touchmove', this.onTouchMove, this);
28692 this.bodyEl.on('touchend', this.onTouchEnd, this);
28696 this.bodyEl.on('mousedown', this.onMouseDown, this);
28697 this.bodyEl.on('mousemove', this.onMouseMove, this);
28698 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
28699 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
28700 Roo.get(document).on('mouseup', this.onMouseUp, this);
28703 this.selectorEl.on('change', this.onFileSelected, this);
28709 this.baseScale = 1;
28711 this.baseRotate = 1;
28712 this.dragable = false;
28713 this.pinching = false;
28716 this.cropData = false;
28717 this.notifyEl.dom.innerHTML = this.emptyText;
28719 this.selectorEl.dom.value = '';
28723 resize : function()
28725 if(this.fireEvent('resize', this) != false){
28726 this.setThumbBoxPosition();
28727 this.setCanvasPosition();
28731 onFooterButtonClick : function(e, el, o, type)
28734 case 'rotate-left' :
28735 this.onRotateLeft(e);
28737 case 'rotate-right' :
28738 this.onRotateRight(e);
28741 this.beforeSelectFile(e);
28756 this.fireEvent('footerbuttonclick', this, type);
28759 beforeSelectFile : function(e)
28761 e.preventDefault();
28763 if(this.fireEvent('beforeselectfile', this) != false){
28764 this.selectorEl.dom.click();
28768 onFileSelected : function(e)
28770 e.preventDefault();
28772 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28776 var file = this.selectorEl.dom.files[0];
28778 if(this.fireEvent('inspect', this, file) != false){
28779 this.prepare(file);
28784 trash : function(e)
28786 this.fireEvent('trash', this);
28789 download : function(e)
28791 this.fireEvent('download', this);
28794 loadCanvas : function(src)
28796 if(this.fireEvent('beforeloadcanvas', this, src) != false){
28800 this.imageEl = document.createElement('img');
28804 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
28806 this.imageEl.src = src;
28810 onLoadCanvas : function()
28812 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
28813 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
28815 this.bodyEl.un('click', this.beforeSelectFile, this);
28817 this.notifyEl.hide();
28818 this.thumbEl.show();
28819 this.footerEl.show();
28821 this.baseRotateLevel();
28823 if(this.isDocument){
28824 this.setThumbBoxSize();
28827 this.setThumbBoxPosition();
28829 this.baseScaleLevel();
28835 this.canvasLoaded = true;
28838 this.maskEl.unmask();
28843 setCanvasPosition : function()
28845 if(!this.canvasEl){
28849 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
28850 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
28852 this.previewEl.setLeft(pw);
28853 this.previewEl.setTop(ph);
28857 onMouseDown : function(e)
28861 this.dragable = true;
28862 this.pinching = false;
28864 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
28865 this.dragable = false;
28869 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28870 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28874 onMouseMove : function(e)
28878 if(!this.canvasLoaded){
28882 if (!this.dragable){
28886 var minX = Math.ceil(this.thumbEl.getLeft(true));
28887 var minY = Math.ceil(this.thumbEl.getTop(true));
28889 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
28890 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
28892 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28893 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28895 x = x - this.mouseX;
28896 y = y - this.mouseY;
28898 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
28899 var bgY = Math.ceil(y + this.previewEl.getTop(true));
28901 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
28902 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
28904 this.previewEl.setLeft(bgX);
28905 this.previewEl.setTop(bgY);
28907 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28908 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28911 onMouseUp : function(e)
28915 this.dragable = false;
28918 onMouseWheel : function(e)
28922 this.startScale = this.scale;
28924 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
28926 if(!this.zoomable()){
28927 this.scale = this.startScale;
28936 zoomable : function()
28938 var minScale = this.thumbEl.getWidth() / this.minWidth;
28940 if(this.minWidth < this.minHeight){
28941 minScale = this.thumbEl.getHeight() / this.minHeight;
28944 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
28945 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
28949 (this.rotate == 0 || this.rotate == 180) &&
28951 width > this.imageEl.OriginWidth ||
28952 height > this.imageEl.OriginHeight ||
28953 (width < this.minWidth && height < this.minHeight)
28961 (this.rotate == 90 || this.rotate == 270) &&
28963 width > this.imageEl.OriginWidth ||
28964 height > this.imageEl.OriginHeight ||
28965 (width < this.minHeight && height < this.minWidth)
28972 !this.isDocument &&
28973 (this.rotate == 0 || this.rotate == 180) &&
28975 width < this.minWidth ||
28976 width > this.imageEl.OriginWidth ||
28977 height < this.minHeight ||
28978 height > this.imageEl.OriginHeight
28985 !this.isDocument &&
28986 (this.rotate == 90 || this.rotate == 270) &&
28988 width < this.minHeight ||
28989 width > this.imageEl.OriginWidth ||
28990 height < this.minWidth ||
28991 height > this.imageEl.OriginHeight
29001 onRotateLeft : function(e)
29003 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29005 var minScale = this.thumbEl.getWidth() / this.minWidth;
29007 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29008 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29010 this.startScale = this.scale;
29012 while (this.getScaleLevel() < minScale){
29014 this.scale = this.scale + 1;
29016 if(!this.zoomable()){
29021 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29022 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29027 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29034 this.scale = this.startScale;
29036 this.onRotateFail();
29041 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29043 if(this.isDocument){
29044 this.setThumbBoxSize();
29045 this.setThumbBoxPosition();
29046 this.setCanvasPosition();
29051 this.fireEvent('rotate', this, 'left');
29055 onRotateRight : function(e)
29057 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29059 var minScale = this.thumbEl.getWidth() / this.minWidth;
29061 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29062 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29064 this.startScale = this.scale;
29066 while (this.getScaleLevel() < minScale){
29068 this.scale = this.scale + 1;
29070 if(!this.zoomable()){
29075 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29076 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29081 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29088 this.scale = this.startScale;
29090 this.onRotateFail();
29095 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29097 if(this.isDocument){
29098 this.setThumbBoxSize();
29099 this.setThumbBoxPosition();
29100 this.setCanvasPosition();
29105 this.fireEvent('rotate', this, 'right');
29108 onRotateFail : function()
29110 this.errorEl.show(true);
29114 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
29119 this.previewEl.dom.innerHTML = '';
29121 var canvasEl = document.createElement("canvas");
29123 var contextEl = canvasEl.getContext("2d");
29125 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29126 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29127 var center = this.imageEl.OriginWidth / 2;
29129 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
29130 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29131 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29132 center = this.imageEl.OriginHeight / 2;
29135 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
29137 contextEl.translate(center, center);
29138 contextEl.rotate(this.rotate * Math.PI / 180);
29140 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29142 this.canvasEl = document.createElement("canvas");
29144 this.contextEl = this.canvasEl.getContext("2d");
29146 switch (this.rotate) {
29149 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29150 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29152 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29157 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29158 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29160 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29161 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);
29165 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29170 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29171 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29173 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29174 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);
29178 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);
29183 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29184 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29186 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29187 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29191 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);
29198 this.previewEl.appendChild(this.canvasEl);
29200 this.setCanvasPosition();
29205 if(!this.canvasLoaded){
29209 var imageCanvas = document.createElement("canvas");
29211 var imageContext = imageCanvas.getContext("2d");
29213 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29214 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29216 var center = imageCanvas.width / 2;
29218 imageContext.translate(center, center);
29220 imageContext.rotate(this.rotate * Math.PI / 180);
29222 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29224 var canvas = document.createElement("canvas");
29226 var context = canvas.getContext("2d");
29228 canvas.width = this.minWidth;
29229 canvas.height = this.minHeight;
29231 switch (this.rotate) {
29234 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
29235 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
29237 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29238 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29240 var targetWidth = this.minWidth - 2 * x;
29241 var targetHeight = this.minHeight - 2 * y;
29245 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29246 scale = targetWidth / width;
29249 if(x > 0 && y == 0){
29250 scale = targetHeight / height;
29253 if(x > 0 && y > 0){
29254 scale = targetWidth / width;
29256 if(width < height){
29257 scale = targetHeight / height;
29261 context.scale(scale, scale);
29263 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29264 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29266 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29267 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29269 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29274 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
29275 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
29277 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29278 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29280 var targetWidth = this.minWidth - 2 * x;
29281 var targetHeight = this.minHeight - 2 * y;
29285 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29286 scale = targetWidth / width;
29289 if(x > 0 && y == 0){
29290 scale = targetHeight / height;
29293 if(x > 0 && y > 0){
29294 scale = targetWidth / width;
29296 if(width < height){
29297 scale = targetHeight / height;
29301 context.scale(scale, scale);
29303 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29304 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29306 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29307 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29309 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
29311 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29316 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
29317 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
29319 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29320 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29322 var targetWidth = this.minWidth - 2 * x;
29323 var targetHeight = this.minHeight - 2 * y;
29327 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29328 scale = targetWidth / width;
29331 if(x > 0 && y == 0){
29332 scale = targetHeight / height;
29335 if(x > 0 && y > 0){
29336 scale = targetWidth / width;
29338 if(width < height){
29339 scale = targetHeight / height;
29343 context.scale(scale, scale);
29345 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29346 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29348 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29349 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29351 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
29352 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
29354 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29359 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
29360 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
29362 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29363 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29365 var targetWidth = this.minWidth - 2 * x;
29366 var targetHeight = this.minHeight - 2 * y;
29370 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29371 scale = targetWidth / width;
29374 if(x > 0 && y == 0){
29375 scale = targetHeight / height;
29378 if(x > 0 && y > 0){
29379 scale = targetWidth / width;
29381 if(width < height){
29382 scale = targetHeight / height;
29386 context.scale(scale, scale);
29388 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29389 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29391 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29392 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29394 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
29396 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29403 this.cropData = canvas.toDataURL(this.cropType);
29405 if(this.fireEvent('crop', this, this.cropData) !== false){
29406 this.process(this.file, this.cropData);
29413 setThumbBoxSize : function()
29417 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
29418 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
29419 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
29421 this.minWidth = width;
29422 this.minHeight = height;
29424 if(this.rotate == 90 || this.rotate == 270){
29425 this.minWidth = height;
29426 this.minHeight = width;
29431 width = Math.ceil(this.minWidth * height / this.minHeight);
29433 if(this.minWidth > this.minHeight){
29435 height = Math.ceil(this.minHeight * width / this.minWidth);
29438 this.thumbEl.setStyle({
29439 width : width + 'px',
29440 height : height + 'px'
29447 setThumbBoxPosition : function()
29449 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
29450 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
29452 this.thumbEl.setLeft(x);
29453 this.thumbEl.setTop(y);
29457 baseRotateLevel : function()
29459 this.baseRotate = 1;
29462 typeof(this.exif) != 'undefined' &&
29463 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
29464 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
29466 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
29469 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
29473 baseScaleLevel : function()
29477 if(this.isDocument){
29479 if(this.baseRotate == 6 || this.baseRotate == 8){
29481 height = this.thumbEl.getHeight();
29482 this.baseScale = height / this.imageEl.OriginWidth;
29484 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
29485 width = this.thumbEl.getWidth();
29486 this.baseScale = width / this.imageEl.OriginHeight;
29492 height = this.thumbEl.getHeight();
29493 this.baseScale = height / this.imageEl.OriginHeight;
29495 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
29496 width = this.thumbEl.getWidth();
29497 this.baseScale = width / this.imageEl.OriginWidth;
29503 if(this.baseRotate == 6 || this.baseRotate == 8){
29505 width = this.thumbEl.getHeight();
29506 this.baseScale = width / this.imageEl.OriginHeight;
29508 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
29509 height = this.thumbEl.getWidth();
29510 this.baseScale = height / this.imageEl.OriginHeight;
29513 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29514 height = this.thumbEl.getWidth();
29515 this.baseScale = height / this.imageEl.OriginHeight;
29517 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
29518 width = this.thumbEl.getHeight();
29519 this.baseScale = width / this.imageEl.OriginWidth;
29526 width = this.thumbEl.getWidth();
29527 this.baseScale = width / this.imageEl.OriginWidth;
29529 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
29530 height = this.thumbEl.getHeight();
29531 this.baseScale = height / this.imageEl.OriginHeight;
29534 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29536 height = this.thumbEl.getHeight();
29537 this.baseScale = height / this.imageEl.OriginHeight;
29539 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
29540 width = this.thumbEl.getWidth();
29541 this.baseScale = width / this.imageEl.OriginWidth;
29549 getScaleLevel : function()
29551 return this.baseScale * Math.pow(1.1, this.scale);
29554 onTouchStart : function(e)
29556 if(!this.canvasLoaded){
29557 this.beforeSelectFile(e);
29561 var touches = e.browserEvent.touches;
29567 if(touches.length == 1){
29568 this.onMouseDown(e);
29572 if(touches.length != 2){
29578 for(var i = 0, finger; finger = touches[i]; i++){
29579 coords.push(finger.pageX, finger.pageY);
29582 var x = Math.pow(coords[0] - coords[2], 2);
29583 var y = Math.pow(coords[1] - coords[3], 2);
29585 this.startDistance = Math.sqrt(x + y);
29587 this.startScale = this.scale;
29589 this.pinching = true;
29590 this.dragable = false;
29594 onTouchMove : function(e)
29596 if(!this.pinching && !this.dragable){
29600 var touches = e.browserEvent.touches;
29607 this.onMouseMove(e);
29613 for(var i = 0, finger; finger = touches[i]; i++){
29614 coords.push(finger.pageX, finger.pageY);
29617 var x = Math.pow(coords[0] - coords[2], 2);
29618 var y = Math.pow(coords[1] - coords[3], 2);
29620 this.endDistance = Math.sqrt(x + y);
29622 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
29624 if(!this.zoomable()){
29625 this.scale = this.startScale;
29633 onTouchEnd : function(e)
29635 this.pinching = false;
29636 this.dragable = false;
29640 process : function(file, crop)
29643 this.maskEl.mask(this.loadingText);
29646 this.xhr = new XMLHttpRequest();
29648 file.xhr = this.xhr;
29650 this.xhr.open(this.method, this.url, true);
29653 "Accept": "application/json",
29654 "Cache-Control": "no-cache",
29655 "X-Requested-With": "XMLHttpRequest"
29658 for (var headerName in headers) {
29659 var headerValue = headers[headerName];
29661 this.xhr.setRequestHeader(headerName, headerValue);
29667 this.xhr.onload = function()
29669 _this.xhrOnLoad(_this.xhr);
29672 this.xhr.onerror = function()
29674 _this.xhrOnError(_this.xhr);
29677 var formData = new FormData();
29679 formData.append('returnHTML', 'NO');
29682 formData.append('crop', crop);
29685 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
29686 formData.append(this.paramName, file, file.name);
29689 if(typeof(file.filename) != 'undefined'){
29690 formData.append('filename', file.filename);
29693 if(typeof(file.mimetype) != 'undefined'){
29694 formData.append('mimetype', file.mimetype);
29697 if(this.fireEvent('arrange', this, formData) != false){
29698 this.xhr.send(formData);
29702 xhrOnLoad : function(xhr)
29705 this.maskEl.unmask();
29708 if (xhr.readyState !== 4) {
29709 this.fireEvent('exception', this, xhr);
29713 var response = Roo.decode(xhr.responseText);
29715 if(!response.success){
29716 this.fireEvent('exception', this, xhr);
29720 var response = Roo.decode(xhr.responseText);
29722 this.fireEvent('upload', this, response);
29726 xhrOnError : function()
29729 this.maskEl.unmask();
29732 Roo.log('xhr on error');
29734 var response = Roo.decode(xhr.responseText);
29740 prepare : function(file)
29743 this.maskEl.mask(this.loadingText);
29749 if(typeof(file) === 'string'){
29750 this.loadCanvas(file);
29754 if(!file || !this.urlAPI){
29759 this.cropType = file.type;
29763 if(this.fireEvent('prepare', this, this.file) != false){
29765 var reader = new FileReader();
29767 reader.onload = function (e) {
29768 if (e.target.error) {
29769 Roo.log(e.target.error);
29773 var buffer = e.target.result,
29774 dataView = new DataView(buffer),
29776 maxOffset = dataView.byteLength - 4,
29780 if (dataView.getUint16(0) === 0xffd8) {
29781 while (offset < maxOffset) {
29782 markerBytes = dataView.getUint16(offset);
29784 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
29785 markerLength = dataView.getUint16(offset + 2) + 2;
29786 if (offset + markerLength > dataView.byteLength) {
29787 Roo.log('Invalid meta data: Invalid segment size.');
29791 if(markerBytes == 0xffe1){
29792 _this.parseExifData(
29799 offset += markerLength;
29809 var url = _this.urlAPI.createObjectURL(_this.file);
29811 _this.loadCanvas(url);
29816 reader.readAsArrayBuffer(this.file);
29822 parseExifData : function(dataView, offset, length)
29824 var tiffOffset = offset + 10,
29828 if (dataView.getUint32(offset + 4) !== 0x45786966) {
29829 // No Exif data, might be XMP data instead
29833 // Check for the ASCII code for "Exif" (0x45786966):
29834 if (dataView.getUint32(offset + 4) !== 0x45786966) {
29835 // No Exif data, might be XMP data instead
29838 if (tiffOffset + 8 > dataView.byteLength) {
29839 Roo.log('Invalid Exif data: Invalid segment size.');
29842 // Check for the two null bytes:
29843 if (dataView.getUint16(offset + 8) !== 0x0000) {
29844 Roo.log('Invalid Exif data: Missing byte alignment offset.');
29847 // Check the byte alignment:
29848 switch (dataView.getUint16(tiffOffset)) {
29850 littleEndian = true;
29853 littleEndian = false;
29856 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
29859 // Check for the TIFF tag marker (0x002A):
29860 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
29861 Roo.log('Invalid Exif data: Missing TIFF marker.');
29864 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
29865 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
29867 this.parseExifTags(
29870 tiffOffset + dirOffset,
29875 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
29880 if (dirOffset + 6 > dataView.byteLength) {
29881 Roo.log('Invalid Exif data: Invalid directory offset.');
29884 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
29885 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
29886 if (dirEndOffset + 4 > dataView.byteLength) {
29887 Roo.log('Invalid Exif data: Invalid directory size.');
29890 for (i = 0; i < tagsNumber; i += 1) {
29894 dirOffset + 2 + 12 * i, // tag offset
29898 // Return the offset to the next directory:
29899 return dataView.getUint32(dirEndOffset, littleEndian);
29902 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
29904 var tag = dataView.getUint16(offset, littleEndian);
29906 this.exif[tag] = this.getExifValue(
29910 dataView.getUint16(offset + 2, littleEndian), // tag type
29911 dataView.getUint32(offset + 4, littleEndian), // tag length
29916 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
29918 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
29927 Roo.log('Invalid Exif data: Invalid tag type.');
29931 tagSize = tagType.size * length;
29932 // Determine if the value is contained in the dataOffset bytes,
29933 // or if the value at the dataOffset is a pointer to the actual data:
29934 dataOffset = tagSize > 4 ?
29935 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
29936 if (dataOffset + tagSize > dataView.byteLength) {
29937 Roo.log('Invalid Exif data: Invalid data offset.');
29940 if (length === 1) {
29941 return tagType.getValue(dataView, dataOffset, littleEndian);
29944 for (i = 0; i < length; i += 1) {
29945 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
29948 if (tagType.ascii) {
29950 // Concatenate the chars:
29951 for (i = 0; i < values.length; i += 1) {
29953 // Ignore the terminating NULL byte(s):
29954 if (c === '\u0000') {
29966 Roo.apply(Roo.bootstrap.UploadCropbox, {
29968 'Orientation': 0x0112
29972 1: 0, //'top-left',
29974 3: 180, //'bottom-right',
29975 // 4: 'bottom-left',
29977 6: 90, //'right-top',
29978 // 7: 'right-bottom',
29979 8: 270 //'left-bottom'
29983 // byte, 8-bit unsigned int:
29985 getValue: function (dataView, dataOffset) {
29986 return dataView.getUint8(dataOffset);
29990 // ascii, 8-bit byte:
29992 getValue: function (dataView, dataOffset) {
29993 return String.fromCharCode(dataView.getUint8(dataOffset));
29998 // short, 16 bit int:
30000 getValue: function (dataView, dataOffset, littleEndian) {
30001 return dataView.getUint16(dataOffset, littleEndian);
30005 // long, 32 bit int:
30007 getValue: function (dataView, dataOffset, littleEndian) {
30008 return dataView.getUint32(dataOffset, littleEndian);
30012 // rational = two long values, first is numerator, second is denominator:
30014 getValue: function (dataView, dataOffset, littleEndian) {
30015 return dataView.getUint32(dataOffset, littleEndian) /
30016 dataView.getUint32(dataOffset + 4, littleEndian);
30020 // slong, 32 bit signed int:
30022 getValue: function (dataView, dataOffset, littleEndian) {
30023 return dataView.getInt32(dataOffset, littleEndian);
30027 // srational, two slongs, first is numerator, second is denominator:
30029 getValue: function (dataView, dataOffset, littleEndian) {
30030 return dataView.getInt32(dataOffset, littleEndian) /
30031 dataView.getInt32(dataOffset + 4, littleEndian);
30041 cls : 'btn-group roo-upload-cropbox-rotate-left',
30042 action : 'rotate-left',
30046 cls : 'btn btn-default',
30047 html : '<i class="fa fa-undo"></i>'
30053 cls : 'btn-group roo-upload-cropbox-picture',
30054 action : 'picture',
30058 cls : 'btn btn-default',
30059 html : '<i class="fa fa-picture-o"></i>'
30065 cls : 'btn-group roo-upload-cropbox-rotate-right',
30066 action : 'rotate-right',
30070 cls : 'btn btn-default',
30071 html : '<i class="fa fa-repeat"></i>'
30079 cls : 'btn-group roo-upload-cropbox-rotate-left',
30080 action : 'rotate-left',
30084 cls : 'btn btn-default',
30085 html : '<i class="fa fa-undo"></i>'
30091 cls : 'btn-group roo-upload-cropbox-download',
30092 action : 'download',
30096 cls : 'btn btn-default',
30097 html : '<i class="fa fa-download"></i>'
30103 cls : 'btn-group roo-upload-cropbox-crop',
30108 cls : 'btn btn-default',
30109 html : '<i class="fa fa-crop"></i>'
30115 cls : 'btn-group roo-upload-cropbox-trash',
30120 cls : 'btn btn-default',
30121 html : '<i class="fa fa-trash"></i>'
30127 cls : 'btn-group roo-upload-cropbox-rotate-right',
30128 action : 'rotate-right',
30132 cls : 'btn btn-default',
30133 html : '<i class="fa fa-repeat"></i>'
30141 cls : 'btn-group roo-upload-cropbox-rotate-left',
30142 action : 'rotate-left',
30146 cls : 'btn btn-default',
30147 html : '<i class="fa fa-undo"></i>'
30153 cls : 'btn-group roo-upload-cropbox-rotate-right',
30154 action : 'rotate-right',
30158 cls : 'btn btn-default',
30159 html : '<i class="fa fa-repeat"></i>'
30172 * @class Roo.bootstrap.DocumentManager
30173 * @extends Roo.bootstrap.Component
30174 * Bootstrap DocumentManager class
30175 * @cfg {String} paramName default 'imageUpload'
30176 * @cfg {String} toolTipName default 'filename'
30177 * @cfg {String} method default POST
30178 * @cfg {String} url action url
30179 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
30180 * @cfg {Boolean} multiple multiple upload default true
30181 * @cfg {Number} thumbSize default 300
30182 * @cfg {String} fieldLabel
30183 * @cfg {Number} labelWidth default 4
30184 * @cfg {String} labelAlign (left|top) default left
30185 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
30186 * @cfg {Number} labellg set the width of label (1-12)
30187 * @cfg {Number} labelmd set the width of label (1-12)
30188 * @cfg {Number} labelsm set the width of label (1-12)
30189 * @cfg {Number} labelxs set the width of label (1-12)
30192 * Create a new DocumentManager
30193 * @param {Object} config The config object
30196 Roo.bootstrap.DocumentManager = function(config){
30197 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
30200 this.delegates = [];
30205 * Fire when initial the DocumentManager
30206 * @param {Roo.bootstrap.DocumentManager} this
30211 * inspect selected file
30212 * @param {Roo.bootstrap.DocumentManager} this
30213 * @param {File} file
30218 * Fire when xhr load exception
30219 * @param {Roo.bootstrap.DocumentManager} this
30220 * @param {XMLHttpRequest} xhr
30222 "exception" : true,
30224 * @event afterupload
30225 * Fire when xhr load exception
30226 * @param {Roo.bootstrap.DocumentManager} this
30227 * @param {XMLHttpRequest} xhr
30229 "afterupload" : true,
30232 * prepare the form data
30233 * @param {Roo.bootstrap.DocumentManager} this
30234 * @param {Object} formData
30239 * Fire when remove the file
30240 * @param {Roo.bootstrap.DocumentManager} this
30241 * @param {Object} file
30246 * Fire after refresh the file
30247 * @param {Roo.bootstrap.DocumentManager} this
30252 * Fire after click the image
30253 * @param {Roo.bootstrap.DocumentManager} this
30254 * @param {Object} file
30259 * Fire when upload a image and editable set to true
30260 * @param {Roo.bootstrap.DocumentManager} this
30261 * @param {Object} file
30265 * @event beforeselectfile
30266 * Fire before select file
30267 * @param {Roo.bootstrap.DocumentManager} this
30269 "beforeselectfile" : true,
30272 * Fire before process file
30273 * @param {Roo.bootstrap.DocumentManager} this
30274 * @param {Object} file
30278 * @event previewrendered
30279 * Fire when preview rendered
30280 * @param {Roo.bootstrap.DocumentManager} this
30281 * @param {Object} file
30283 "previewrendered" : true,
30286 "previewResize" : true
30291 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
30300 paramName : 'imageUpload',
30301 toolTipName : 'filename',
30304 labelAlign : 'left',
30314 getAutoCreate : function()
30316 var managerWidget = {
30318 cls : 'roo-document-manager',
30322 cls : 'roo-document-manager-selector',
30327 cls : 'roo-document-manager-uploader',
30331 cls : 'roo-document-manager-upload-btn',
30332 html : '<i class="fa fa-plus"></i>'
30343 cls : 'column col-md-12',
30348 if(this.fieldLabel.length){
30353 cls : 'column col-md-12',
30354 html : this.fieldLabel
30358 cls : 'column col-md-12',
30363 if(this.labelAlign == 'left'){
30368 html : this.fieldLabel
30377 if(this.labelWidth > 12){
30378 content[0].style = "width: " + this.labelWidth + 'px';
30381 if(this.labelWidth < 13 && this.labelmd == 0){
30382 this.labelmd = this.labelWidth;
30385 if(this.labellg > 0){
30386 content[0].cls += ' col-lg-' + this.labellg;
30387 content[1].cls += ' col-lg-' + (12 - this.labellg);
30390 if(this.labelmd > 0){
30391 content[0].cls += ' col-md-' + this.labelmd;
30392 content[1].cls += ' col-md-' + (12 - this.labelmd);
30395 if(this.labelsm > 0){
30396 content[0].cls += ' col-sm-' + this.labelsm;
30397 content[1].cls += ' col-sm-' + (12 - this.labelsm);
30400 if(this.labelxs > 0){
30401 content[0].cls += ' col-xs-' + this.labelxs;
30402 content[1].cls += ' col-xs-' + (12 - this.labelxs);
30410 cls : 'row clearfix',
30418 initEvents : function()
30420 this.managerEl = this.el.select('.roo-document-manager', true).first();
30421 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30423 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
30424 this.selectorEl.hide();
30427 this.selectorEl.attr('multiple', 'multiple');
30430 this.selectorEl.on('change', this.onFileSelected, this);
30432 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
30433 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30435 this.uploader.on('click', this.onUploaderClick, this);
30437 this.renderProgressDialog();
30441 window.addEventListener("resize", function() { _this.refresh(); } );
30443 this.fireEvent('initial', this);
30446 renderProgressDialog : function()
30450 this.progressDialog = new Roo.bootstrap.Modal({
30451 cls : 'roo-document-manager-progress-dialog',
30452 allow_close : false,
30463 btnclick : function() {
30464 _this.uploadCancel();
30470 this.progressDialog.render(Roo.get(document.body));
30472 this.progress = new Roo.bootstrap.Progress({
30473 cls : 'roo-document-manager-progress',
30478 this.progress.render(this.progressDialog.getChildContainer());
30480 this.progressBar = new Roo.bootstrap.ProgressBar({
30481 cls : 'roo-document-manager-progress-bar',
30484 aria_valuemax : 12,
30488 this.progressBar.render(this.progress.getChildContainer());
30491 onUploaderClick : function(e)
30493 e.preventDefault();
30495 if(this.fireEvent('beforeselectfile', this) != false){
30496 this.selectorEl.dom.click();
30501 onFileSelected : function(e)
30503 e.preventDefault();
30505 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
30509 Roo.each(this.selectorEl.dom.files, function(file){
30510 if(this.fireEvent('inspect', this, file) != false){
30511 this.files.push(file);
30521 this.selectorEl.dom.value = '';
30523 if(!this.files || !this.files.length){
30527 if(this.boxes > 0 && this.files.length > this.boxes){
30528 this.files = this.files.slice(0, this.boxes);
30531 this.uploader.show();
30533 if(this.boxes > 0 && this.files.length > this.boxes - 1){
30534 this.uploader.hide();
30543 Roo.each(this.files, function(file){
30545 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
30546 var f = this.renderPreview(file);
30551 if(file.type.indexOf('image') != -1){
30552 this.delegates.push(
30554 _this.process(file);
30555 }).createDelegate(this)
30563 _this.process(file);
30564 }).createDelegate(this)
30569 this.files = files;
30571 this.delegates = this.delegates.concat(docs);
30573 if(!this.delegates.length){
30578 this.progressBar.aria_valuemax = this.delegates.length;
30585 arrange : function()
30587 if(!this.delegates.length){
30588 this.progressDialog.hide();
30593 var delegate = this.delegates.shift();
30595 this.progressDialog.show();
30597 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
30599 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
30604 refresh : function()
30606 this.uploader.show();
30608 if(this.boxes > 0 && this.files.length > this.boxes - 1){
30609 this.uploader.hide();
30612 Roo.isTouch ? this.closable(false) : this.closable(true);
30614 this.fireEvent('refresh', this);
30617 onRemove : function(e, el, o)
30619 e.preventDefault();
30621 this.fireEvent('remove', this, o);
30625 remove : function(o)
30629 Roo.each(this.files, function(file){
30630 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
30639 this.files = files;
30646 Roo.each(this.files, function(file){
30651 file.target.remove();
30660 onClick : function(e, el, o)
30662 e.preventDefault();
30664 this.fireEvent('click', this, o);
30668 closable : function(closable)
30670 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
30672 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30684 xhrOnLoad : function(xhr)
30686 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
30690 if (xhr.readyState !== 4) {
30692 this.fireEvent('exception', this, xhr);
30696 var response = Roo.decode(xhr.responseText);
30698 if(!response.success){
30700 this.fireEvent('exception', this, xhr);
30704 var file = this.renderPreview(response.data);
30706 this.files.push(file);
30710 this.fireEvent('afterupload', this, xhr);
30714 xhrOnError : function(xhr)
30716 Roo.log('xhr on error');
30718 var response = Roo.decode(xhr.responseText);
30725 process : function(file)
30727 if(this.fireEvent('process', this, file) !== false){
30728 if(this.editable && file.type.indexOf('image') != -1){
30729 this.fireEvent('edit', this, file);
30733 this.uploadStart(file, false);
30740 uploadStart : function(file, crop)
30742 this.xhr = new XMLHttpRequest();
30744 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
30749 file.xhr = this.xhr;
30751 this.managerEl.createChild({
30753 cls : 'roo-document-manager-loading',
30757 tooltip : file.name,
30758 cls : 'roo-document-manager-thumb',
30759 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
30765 this.xhr.open(this.method, this.url, true);
30768 "Accept": "application/json",
30769 "Cache-Control": "no-cache",
30770 "X-Requested-With": "XMLHttpRequest"
30773 for (var headerName in headers) {
30774 var headerValue = headers[headerName];
30776 this.xhr.setRequestHeader(headerName, headerValue);
30782 this.xhr.onload = function()
30784 _this.xhrOnLoad(_this.xhr);
30787 this.xhr.onerror = function()
30789 _this.xhrOnError(_this.xhr);
30792 var formData = new FormData();
30794 formData.append('returnHTML', 'NO');
30797 formData.append('crop', crop);
30800 formData.append(this.paramName, file, file.name);
30807 if(this.fireEvent('prepare', this, formData, options) != false){
30809 if(options.manually){
30813 this.xhr.send(formData);
30817 this.uploadCancel();
30820 uploadCancel : function()
30826 this.delegates = [];
30828 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
30835 renderPreview : function(file)
30837 if(typeof(file.target) != 'undefined' && file.target){
30841 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
30843 var previewEl = this.managerEl.createChild({
30845 cls : 'roo-document-manager-preview',
30849 tooltip : file[this.toolTipName],
30850 cls : 'roo-document-manager-thumb',
30851 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
30856 html : '<i class="fa fa-times-circle"></i>'
30861 var close = previewEl.select('button.close', true).first();
30863 close.on('click', this.onRemove, this, file);
30865 file.target = previewEl;
30867 var image = previewEl.select('img', true).first();
30871 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
30873 image.on('click', this.onClick, this, file);
30875 this.fireEvent('previewrendered', this, file);
30881 onPreviewLoad : function(file, image)
30883 if(typeof(file.target) == 'undefined' || !file.target){
30887 var width = image.dom.naturalWidth || image.dom.width;
30888 var height = image.dom.naturalHeight || image.dom.height;
30890 if(!this.previewResize) {
30894 if(width > height){
30895 file.target.addClass('wide');
30899 file.target.addClass('tall');
30904 uploadFromSource : function(file, crop)
30906 this.xhr = new XMLHttpRequest();
30908 this.managerEl.createChild({
30910 cls : 'roo-document-manager-loading',
30914 tooltip : file.name,
30915 cls : 'roo-document-manager-thumb',
30916 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
30922 this.xhr.open(this.method, this.url, true);
30925 "Accept": "application/json",
30926 "Cache-Control": "no-cache",
30927 "X-Requested-With": "XMLHttpRequest"
30930 for (var headerName in headers) {
30931 var headerValue = headers[headerName];
30933 this.xhr.setRequestHeader(headerName, headerValue);
30939 this.xhr.onload = function()
30941 _this.xhrOnLoad(_this.xhr);
30944 this.xhr.onerror = function()
30946 _this.xhrOnError(_this.xhr);
30949 var formData = new FormData();
30951 formData.append('returnHTML', 'NO');
30953 formData.append('crop', crop);
30955 if(typeof(file.filename) != 'undefined'){
30956 formData.append('filename', file.filename);
30959 if(typeof(file.mimetype) != 'undefined'){
30960 formData.append('mimetype', file.mimetype);
30965 if(this.fireEvent('prepare', this, formData) != false){
30966 this.xhr.send(formData);
30976 * @class Roo.bootstrap.DocumentViewer
30977 * @extends Roo.bootstrap.Component
30978 * Bootstrap DocumentViewer class
30979 * @cfg {Boolean} showDownload (true|false) show download button (default true)
30980 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
30983 * Create a new DocumentViewer
30984 * @param {Object} config The config object
30987 Roo.bootstrap.DocumentViewer = function(config){
30988 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
30993 * Fire after initEvent
30994 * @param {Roo.bootstrap.DocumentViewer} this
31000 * @param {Roo.bootstrap.DocumentViewer} this
31005 * Fire after download button
31006 * @param {Roo.bootstrap.DocumentViewer} this
31011 * Fire after trash button
31012 * @param {Roo.bootstrap.DocumentViewer} this
31019 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
31021 showDownload : true,
31025 getAutoCreate : function()
31029 cls : 'roo-document-viewer',
31033 cls : 'roo-document-viewer-body',
31037 cls : 'roo-document-viewer-thumb',
31041 cls : 'roo-document-viewer-image'
31049 cls : 'roo-document-viewer-footer',
31052 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
31056 cls : 'btn-group roo-document-viewer-download',
31060 cls : 'btn btn-default',
31061 html : '<i class="fa fa-download"></i>'
31067 cls : 'btn-group roo-document-viewer-trash',
31071 cls : 'btn btn-default',
31072 html : '<i class="fa fa-trash"></i>'
31085 initEvents : function()
31087 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
31088 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
31090 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
31091 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
31093 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
31094 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
31096 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
31097 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
31099 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
31100 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
31102 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
31103 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
31105 this.bodyEl.on('click', this.onClick, this);
31106 this.downloadBtn.on('click', this.onDownload, this);
31107 this.trashBtn.on('click', this.onTrash, this);
31109 this.downloadBtn.hide();
31110 this.trashBtn.hide();
31112 if(this.showDownload){
31113 this.downloadBtn.show();
31116 if(this.showTrash){
31117 this.trashBtn.show();
31120 if(!this.showDownload && !this.showTrash) {
31121 this.footerEl.hide();
31126 initial : function()
31128 this.fireEvent('initial', this);
31132 onClick : function(e)
31134 e.preventDefault();
31136 this.fireEvent('click', this);
31139 onDownload : function(e)
31141 e.preventDefault();
31143 this.fireEvent('download', this);
31146 onTrash : function(e)
31148 e.preventDefault();
31150 this.fireEvent('trash', this);
31162 * @class Roo.bootstrap.NavProgressBar
31163 * @extends Roo.bootstrap.Component
31164 * Bootstrap NavProgressBar class
31167 * Create a new nav progress bar
31168 * @param {Object} config The config object
31171 Roo.bootstrap.NavProgressBar = function(config){
31172 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
31174 this.bullets = this.bullets || [];
31176 // Roo.bootstrap.NavProgressBar.register(this);
31180 * Fires when the active item changes
31181 * @param {Roo.bootstrap.NavProgressBar} this
31182 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
31183 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
31190 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
31195 getAutoCreate : function()
31197 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
31201 cls : 'roo-navigation-bar-group',
31205 cls : 'roo-navigation-top-bar'
31209 cls : 'roo-navigation-bullets-bar',
31213 cls : 'roo-navigation-bar'
31220 cls : 'roo-navigation-bottom-bar'
31230 initEvents: function()
31235 onRender : function(ct, position)
31237 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
31239 if(this.bullets.length){
31240 Roo.each(this.bullets, function(b){
31249 addItem : function(cfg)
31251 var item = new Roo.bootstrap.NavProgressItem(cfg);
31253 item.parentId = this.id;
31254 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
31257 var top = new Roo.bootstrap.Element({
31259 cls : 'roo-navigation-bar-text'
31262 var bottom = new Roo.bootstrap.Element({
31264 cls : 'roo-navigation-bar-text'
31267 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
31268 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
31270 var topText = new Roo.bootstrap.Element({
31272 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
31275 var bottomText = new Roo.bootstrap.Element({
31277 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
31280 topText.onRender(top.el, null);
31281 bottomText.onRender(bottom.el, null);
31284 item.bottomEl = bottom;
31287 this.barItems.push(item);
31292 getActive : function()
31294 var active = false;
31296 Roo.each(this.barItems, function(v){
31298 if (!v.isActive()) {
31310 setActiveItem : function(item)
31314 Roo.each(this.barItems, function(v){
31315 if (v.rid == item.rid) {
31319 if (v.isActive()) {
31320 v.setActive(false);
31325 item.setActive(true);
31327 this.fireEvent('changed', this, item, prev);
31330 getBarItem: function(rid)
31334 Roo.each(this.barItems, function(e) {
31335 if (e.rid != rid) {
31346 indexOfItem : function(item)
31350 Roo.each(this.barItems, function(v, i){
31352 if (v.rid != item.rid) {
31363 setActiveNext : function()
31365 var i = this.indexOfItem(this.getActive());
31367 if (i > this.barItems.length) {
31371 this.setActiveItem(this.barItems[i+1]);
31374 setActivePrev : function()
31376 var i = this.indexOfItem(this.getActive());
31382 this.setActiveItem(this.barItems[i-1]);
31385 format : function()
31387 if(!this.barItems.length){
31391 var width = 100 / this.barItems.length;
31393 Roo.each(this.barItems, function(i){
31394 i.el.setStyle('width', width + '%');
31395 i.topEl.el.setStyle('width', width + '%');
31396 i.bottomEl.el.setStyle('width', width + '%');
31405 * Nav Progress Item
31410 * @class Roo.bootstrap.NavProgressItem
31411 * @extends Roo.bootstrap.Component
31412 * Bootstrap NavProgressItem class
31413 * @cfg {String} rid the reference id
31414 * @cfg {Boolean} active (true|false) Is item active default false
31415 * @cfg {Boolean} disabled (true|false) Is item active default false
31416 * @cfg {String} html
31417 * @cfg {String} position (top|bottom) text position default bottom
31418 * @cfg {String} icon show icon instead of number
31421 * Create a new NavProgressItem
31422 * @param {Object} config The config object
31424 Roo.bootstrap.NavProgressItem = function(config){
31425 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
31430 * The raw click event for the entire grid.
31431 * @param {Roo.bootstrap.NavProgressItem} this
31432 * @param {Roo.EventObject} e
31439 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
31445 position : 'bottom',
31448 getAutoCreate : function()
31450 var iconCls = 'roo-navigation-bar-item-icon';
31452 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
31456 cls: 'roo-navigation-bar-item',
31466 cfg.cls += ' active';
31469 cfg.cls += ' disabled';
31475 disable : function()
31477 this.setDisabled(true);
31480 enable : function()
31482 this.setDisabled(false);
31485 initEvents: function()
31487 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
31489 this.iconEl.on('click', this.onClick, this);
31492 onClick : function(e)
31494 e.preventDefault();
31500 if(this.fireEvent('click', this, e) === false){
31504 this.parent().setActiveItem(this);
31507 isActive: function ()
31509 return this.active;
31512 setActive : function(state)
31514 if(this.active == state){
31518 this.active = state;
31521 this.el.addClass('active');
31525 this.el.removeClass('active');
31530 setDisabled : function(state)
31532 if(this.disabled == state){
31536 this.disabled = state;
31539 this.el.addClass('disabled');
31543 this.el.removeClass('disabled');
31546 tooltipEl : function()
31548 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
31561 * @class Roo.bootstrap.FieldLabel
31562 * @extends Roo.bootstrap.Component
31563 * Bootstrap FieldLabel class
31564 * @cfg {String} html contents of the element
31565 * @cfg {String} tag tag of the element default label
31566 * @cfg {String} cls class of the element
31567 * @cfg {String} target label target
31568 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
31569 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
31570 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
31571 * @cfg {String} iconTooltip default "This field is required"
31572 * @cfg {String} indicatorpos (left|right) default left
31575 * Create a new FieldLabel
31576 * @param {Object} config The config object
31579 Roo.bootstrap.FieldLabel = function(config){
31580 Roo.bootstrap.Element.superclass.constructor.call(this, config);
31585 * Fires after the field has been marked as invalid.
31586 * @param {Roo.form.FieldLabel} this
31587 * @param {String} msg The validation message
31592 * Fires after the field has been validated with no errors.
31593 * @param {Roo.form.FieldLabel} this
31599 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
31606 invalidClass : 'has-warning',
31607 validClass : 'has-success',
31608 iconTooltip : 'This field is required',
31609 indicatorpos : 'left',
31611 getAutoCreate : function(){
31614 if (!this.allowBlank) {
31620 cls : 'roo-bootstrap-field-label ' + this.cls,
31625 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
31626 tooltip : this.iconTooltip
31635 if(this.indicatorpos == 'right'){
31638 cls : 'roo-bootstrap-field-label ' + this.cls,
31647 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
31648 tooltip : this.iconTooltip
31657 initEvents: function()
31659 Roo.bootstrap.Element.superclass.initEvents.call(this);
31661 this.indicator = this.indicatorEl();
31663 if(this.indicator){
31664 this.indicator.removeClass('visible');
31665 this.indicator.addClass('invisible');
31668 Roo.bootstrap.FieldLabel.register(this);
31671 indicatorEl : function()
31673 var indicator = this.el.select('i.roo-required-indicator',true).first();
31684 * Mark this field as valid
31686 markValid : function()
31688 if(this.indicator){
31689 this.indicator.removeClass('visible');
31690 this.indicator.addClass('invisible');
31692 if (Roo.bootstrap.version == 3) {
31693 this.el.removeClass(this.invalidClass);
31694 this.el.addClass(this.validClass);
31696 this.el.removeClass('is-invalid');
31697 this.el.addClass('is-valid');
31701 this.fireEvent('valid', this);
31705 * Mark this field as invalid
31706 * @param {String} msg The validation message
31708 markInvalid : function(msg)
31710 if(this.indicator){
31711 this.indicator.removeClass('invisible');
31712 this.indicator.addClass('visible');
31714 if (Roo.bootstrap.version == 3) {
31715 this.el.removeClass(this.validClass);
31716 this.el.addClass(this.invalidClass);
31718 this.el.removeClass('is-valid');
31719 this.el.addClass('is-invalid');
31723 this.fireEvent('invalid', this, msg);
31729 Roo.apply(Roo.bootstrap.FieldLabel, {
31734 * register a FieldLabel Group
31735 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
31737 register : function(label)
31739 if(this.groups.hasOwnProperty(label.target)){
31743 this.groups[label.target] = label;
31747 * fetch a FieldLabel Group based on the target
31748 * @param {string} target
31749 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
31751 get: function(target) {
31752 if (typeof(this.groups[target]) == 'undefined') {
31756 return this.groups[target] ;
31765 * page DateSplitField.
31771 * @class Roo.bootstrap.DateSplitField
31772 * @extends Roo.bootstrap.Component
31773 * Bootstrap DateSplitField class
31774 * @cfg {string} fieldLabel - the label associated
31775 * @cfg {Number} labelWidth set the width of label (0-12)
31776 * @cfg {String} labelAlign (top|left)
31777 * @cfg {Boolean} dayAllowBlank (true|false) default false
31778 * @cfg {Boolean} monthAllowBlank (true|false) default false
31779 * @cfg {Boolean} yearAllowBlank (true|false) default false
31780 * @cfg {string} dayPlaceholder
31781 * @cfg {string} monthPlaceholder
31782 * @cfg {string} yearPlaceholder
31783 * @cfg {string} dayFormat default 'd'
31784 * @cfg {string} monthFormat default 'm'
31785 * @cfg {string} yearFormat default 'Y'
31786 * @cfg {Number} labellg set the width of label (1-12)
31787 * @cfg {Number} labelmd set the width of label (1-12)
31788 * @cfg {Number} labelsm set the width of label (1-12)
31789 * @cfg {Number} labelxs set the width of label (1-12)
31793 * Create a new DateSplitField
31794 * @param {Object} config The config object
31797 Roo.bootstrap.DateSplitField = function(config){
31798 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
31804 * getting the data of years
31805 * @param {Roo.bootstrap.DateSplitField} this
31806 * @param {Object} years
31811 * getting the data of days
31812 * @param {Roo.bootstrap.DateSplitField} this
31813 * @param {Object} days
31818 * Fires after the field has been marked as invalid.
31819 * @param {Roo.form.Field} this
31820 * @param {String} msg The validation message
31825 * Fires after the field has been validated with no errors.
31826 * @param {Roo.form.Field} this
31832 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
31835 labelAlign : 'top',
31837 dayAllowBlank : false,
31838 monthAllowBlank : false,
31839 yearAllowBlank : false,
31840 dayPlaceholder : '',
31841 monthPlaceholder : '',
31842 yearPlaceholder : '',
31846 isFormField : true,
31852 getAutoCreate : function()
31856 cls : 'row roo-date-split-field-group',
31861 cls : 'form-hidden-field roo-date-split-field-group-value',
31867 var labelCls = 'col-md-12';
31868 var contentCls = 'col-md-4';
31870 if(this.fieldLabel){
31874 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
31878 html : this.fieldLabel
31883 if(this.labelAlign == 'left'){
31885 if(this.labelWidth > 12){
31886 label.style = "width: " + this.labelWidth + 'px';
31889 if(this.labelWidth < 13 && this.labelmd == 0){
31890 this.labelmd = this.labelWidth;
31893 if(this.labellg > 0){
31894 labelCls = ' col-lg-' + this.labellg;
31895 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
31898 if(this.labelmd > 0){
31899 labelCls = ' col-md-' + this.labelmd;
31900 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
31903 if(this.labelsm > 0){
31904 labelCls = ' col-sm-' + this.labelsm;
31905 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
31908 if(this.labelxs > 0){
31909 labelCls = ' col-xs-' + this.labelxs;
31910 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
31914 label.cls += ' ' + labelCls;
31916 cfg.cn.push(label);
31919 Roo.each(['day', 'month', 'year'], function(t){
31922 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
31929 inputEl: function ()
31931 return this.el.select('.roo-date-split-field-group-value', true).first();
31934 onRender : function(ct, position)
31938 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
31940 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
31942 this.dayField = new Roo.bootstrap.ComboBox({
31943 allowBlank : this.dayAllowBlank,
31944 alwaysQuery : true,
31945 displayField : 'value',
31948 forceSelection : true,
31950 placeholder : this.dayPlaceholder,
31951 selectOnFocus : true,
31952 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
31953 triggerAction : 'all',
31955 valueField : 'value',
31956 store : new Roo.data.SimpleStore({
31957 data : (function() {
31959 _this.fireEvent('days', _this, days);
31962 fields : [ 'value' ]
31965 select : function (_self, record, index)
31967 _this.setValue(_this.getValue());
31972 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
31974 this.monthField = new Roo.bootstrap.MonthField({
31975 after : '<i class=\"fa fa-calendar\"></i>',
31976 allowBlank : this.monthAllowBlank,
31977 placeholder : this.monthPlaceholder,
31980 render : function (_self)
31982 this.el.select('span.input-group-addon', true).first().on('click', function(e){
31983 e.preventDefault();
31987 select : function (_self, oldvalue, newvalue)
31989 _this.setValue(_this.getValue());
31994 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
31996 this.yearField = new Roo.bootstrap.ComboBox({
31997 allowBlank : this.yearAllowBlank,
31998 alwaysQuery : true,
31999 displayField : 'value',
32002 forceSelection : true,
32004 placeholder : this.yearPlaceholder,
32005 selectOnFocus : true,
32006 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32007 triggerAction : 'all',
32009 valueField : 'value',
32010 store : new Roo.data.SimpleStore({
32011 data : (function() {
32013 _this.fireEvent('years', _this, years);
32016 fields : [ 'value' ]
32019 select : function (_self, record, index)
32021 _this.setValue(_this.getValue());
32026 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
32029 setValue : function(v, format)
32031 this.inputEl.dom.value = v;
32033 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
32035 var d = Date.parseDate(v, f);
32042 this.setDay(d.format(this.dayFormat));
32043 this.setMonth(d.format(this.monthFormat));
32044 this.setYear(d.format(this.yearFormat));
32051 setDay : function(v)
32053 this.dayField.setValue(v);
32054 this.inputEl.dom.value = this.getValue();
32059 setMonth : function(v)
32061 this.monthField.setValue(v, true);
32062 this.inputEl.dom.value = this.getValue();
32067 setYear : function(v)
32069 this.yearField.setValue(v);
32070 this.inputEl.dom.value = this.getValue();
32075 getDay : function()
32077 return this.dayField.getValue();
32080 getMonth : function()
32082 return this.monthField.getValue();
32085 getYear : function()
32087 return this.yearField.getValue();
32090 getValue : function()
32092 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
32094 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
32104 this.inputEl.dom.value = '';
32109 validate : function()
32111 var d = this.dayField.validate();
32112 var m = this.monthField.validate();
32113 var y = this.yearField.validate();
32118 (!this.dayAllowBlank && !d) ||
32119 (!this.monthAllowBlank && !m) ||
32120 (!this.yearAllowBlank && !y)
32125 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
32134 this.markInvalid();
32139 markValid : function()
32142 var label = this.el.select('label', true).first();
32143 var icon = this.el.select('i.fa-star', true).first();
32149 this.fireEvent('valid', this);
32153 * Mark this field as invalid
32154 * @param {String} msg The validation message
32156 markInvalid : function(msg)
32159 var label = this.el.select('label', true).first();
32160 var icon = this.el.select('i.fa-star', true).first();
32162 if(label && !icon){
32163 this.el.select('.roo-date-split-field-label', true).createChild({
32165 cls : 'text-danger fa fa-lg fa-star',
32166 tooltip : 'This field is required',
32167 style : 'margin-right:5px;'
32171 this.fireEvent('invalid', this, msg);
32174 clearInvalid : function()
32176 var label = this.el.select('label', true).first();
32177 var icon = this.el.select('i.fa-star', true).first();
32183 this.fireEvent('valid', this);
32186 getName: function()
32196 * http://masonry.desandro.com
32198 * The idea is to render all the bricks based on vertical width...
32200 * The original code extends 'outlayer' - we might need to use that....
32206 * @class Roo.bootstrap.LayoutMasonry
32207 * @extends Roo.bootstrap.Component
32208 * Bootstrap Layout Masonry class
32211 * Create a new Element
32212 * @param {Object} config The config object
32215 Roo.bootstrap.LayoutMasonry = function(config){
32217 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
32221 Roo.bootstrap.LayoutMasonry.register(this);
32227 * Fire after layout the items
32228 * @param {Roo.bootstrap.LayoutMasonry} this
32229 * @param {Roo.EventObject} e
32236 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
32239 * @cfg {Boolean} isLayoutInstant = no animation?
32241 isLayoutInstant : false, // needed?
32244 * @cfg {Number} boxWidth width of the columns
32249 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
32254 * @cfg {Number} padWidth padding below box..
32259 * @cfg {Number} gutter gutter width..
32264 * @cfg {Number} maxCols maximum number of columns
32270 * @cfg {Boolean} isAutoInitial defalut true
32272 isAutoInitial : true,
32277 * @cfg {Boolean} isHorizontal defalut false
32279 isHorizontal : false,
32281 currentSize : null,
32287 bricks: null, //CompositeElement
32291 _isLayoutInited : false,
32293 // isAlternative : false, // only use for vertical layout...
32296 * @cfg {Number} alternativePadWidth padding below box..
32298 alternativePadWidth : 50,
32300 selectedBrick : [],
32302 getAutoCreate : function(){
32304 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
32308 cls: 'blog-masonary-wrapper ' + this.cls,
32310 cls : 'mas-boxes masonary'
32317 getChildContainer: function( )
32319 if (this.boxesEl) {
32320 return this.boxesEl;
32323 this.boxesEl = this.el.select('.mas-boxes').first();
32325 return this.boxesEl;
32329 initEvents : function()
32333 if(this.isAutoInitial){
32334 Roo.log('hook children rendered');
32335 this.on('childrenrendered', function() {
32336 Roo.log('children rendered');
32342 initial : function()
32344 this.selectedBrick = [];
32346 this.currentSize = this.el.getBox(true);
32348 Roo.EventManager.onWindowResize(this.resize, this);
32350 if(!this.isAutoInitial){
32358 //this.layout.defer(500,this);
32362 resize : function()
32364 var cs = this.el.getBox(true);
32367 this.currentSize.width == cs.width &&
32368 this.currentSize.x == cs.x &&
32369 this.currentSize.height == cs.height &&
32370 this.currentSize.y == cs.y
32372 Roo.log("no change in with or X or Y");
32376 this.currentSize = cs;
32382 layout : function()
32384 this._resetLayout();
32386 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32388 this.layoutItems( isInstant );
32390 this._isLayoutInited = true;
32392 this.fireEvent('layout', this);
32396 _resetLayout : function()
32398 if(this.isHorizontal){
32399 this.horizontalMeasureColumns();
32403 this.verticalMeasureColumns();
32407 verticalMeasureColumns : function()
32409 this.getContainerWidth();
32411 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
32412 // this.colWidth = Math.floor(this.containerWidth * 0.8);
32416 var boxWidth = this.boxWidth + this.padWidth;
32418 if(this.containerWidth < this.boxWidth){
32419 boxWidth = this.containerWidth
32422 var containerWidth = this.containerWidth;
32424 var cols = Math.floor(containerWidth / boxWidth);
32426 this.cols = Math.max( cols, 1 );
32428 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32430 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
32432 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
32434 this.colWidth = boxWidth + avail - this.padWidth;
32436 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
32437 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
32440 horizontalMeasureColumns : function()
32442 this.getContainerWidth();
32444 var boxWidth = this.boxWidth;
32446 if(this.containerWidth < boxWidth){
32447 boxWidth = this.containerWidth;
32450 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
32452 this.el.setHeight(boxWidth);
32456 getContainerWidth : function()
32458 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32461 layoutItems : function( isInstant )
32463 Roo.log(this.bricks);
32465 var items = Roo.apply([], this.bricks);
32467 if(this.isHorizontal){
32468 this._horizontalLayoutItems( items , isInstant );
32472 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
32473 // this._verticalAlternativeLayoutItems( items , isInstant );
32477 this._verticalLayoutItems( items , isInstant );
32481 _verticalLayoutItems : function ( items , isInstant)
32483 if ( !items || !items.length ) {
32488 ['xs', 'xs', 'xs', 'tall'],
32489 ['xs', 'xs', 'tall'],
32490 ['xs', 'xs', 'sm'],
32491 ['xs', 'xs', 'xs'],
32497 ['sm', 'xs', 'xs'],
32501 ['tall', 'xs', 'xs', 'xs'],
32502 ['tall', 'xs', 'xs'],
32514 Roo.each(items, function(item, k){
32516 switch (item.size) {
32517 // these layouts take up a full box,
32528 boxes.push([item]);
32551 var filterPattern = function(box, length)
32559 var pattern = box.slice(0, length);
32563 Roo.each(pattern, function(i){
32564 format.push(i.size);
32567 Roo.each(standard, function(s){
32569 if(String(s) != String(format)){
32578 if(!match && length == 1){
32583 filterPattern(box, length - 1);
32587 queue.push(pattern);
32589 box = box.slice(length, box.length);
32591 filterPattern(box, 4);
32597 Roo.each(boxes, function(box, k){
32603 if(box.length == 1){
32608 filterPattern(box, 4);
32612 this._processVerticalLayoutQueue( queue, isInstant );
32616 // _verticalAlternativeLayoutItems : function( items , isInstant )
32618 // if ( !items || !items.length ) {
32622 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
32626 _horizontalLayoutItems : function ( items , isInstant)
32628 if ( !items || !items.length || items.length < 3) {
32634 var eItems = items.slice(0, 3);
32636 items = items.slice(3, items.length);
32639 ['xs', 'xs', 'xs', 'wide'],
32640 ['xs', 'xs', 'wide'],
32641 ['xs', 'xs', 'sm'],
32642 ['xs', 'xs', 'xs'],
32648 ['sm', 'xs', 'xs'],
32652 ['wide', 'xs', 'xs', 'xs'],
32653 ['wide', 'xs', 'xs'],
32666 Roo.each(items, function(item, k){
32668 switch (item.size) {
32679 boxes.push([item]);
32703 var filterPattern = function(box, length)
32711 var pattern = box.slice(0, length);
32715 Roo.each(pattern, function(i){
32716 format.push(i.size);
32719 Roo.each(standard, function(s){
32721 if(String(s) != String(format)){
32730 if(!match && length == 1){
32735 filterPattern(box, length - 1);
32739 queue.push(pattern);
32741 box = box.slice(length, box.length);
32743 filterPattern(box, 4);
32749 Roo.each(boxes, function(box, k){
32755 if(box.length == 1){
32760 filterPattern(box, 4);
32767 var pos = this.el.getBox(true);
32771 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
32773 var hit_end = false;
32775 Roo.each(queue, function(box){
32779 Roo.each(box, function(b){
32781 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32791 Roo.each(box, function(b){
32793 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32796 mx = Math.max(mx, b.x);
32800 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
32804 Roo.each(box, function(b){
32806 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32820 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
32823 /** Sets position of item in DOM
32824 * @param {Element} item
32825 * @param {Number} x - horizontal position
32826 * @param {Number} y - vertical position
32827 * @param {Boolean} isInstant - disables transitions
32829 _processVerticalLayoutQueue : function( queue, isInstant )
32831 var pos = this.el.getBox(true);
32836 for (var i = 0; i < this.cols; i++){
32840 Roo.each(queue, function(box, k){
32842 var col = k % this.cols;
32844 Roo.each(box, function(b,kk){
32846 b.el.position('absolute');
32848 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32849 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32851 if(b.size == 'md-left' || b.size == 'md-right'){
32852 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
32853 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32856 b.el.setWidth(width);
32857 b.el.setHeight(height);
32859 b.el.select('iframe',true).setSize(width,height);
32863 for (var i = 0; i < this.cols; i++){
32865 if(maxY[i] < maxY[col]){
32870 col = Math.min(col, i);
32874 x = pos.x + col * (this.colWidth + this.padWidth);
32878 var positions = [];
32880 switch (box.length){
32882 positions = this.getVerticalOneBoxColPositions(x, y, box);
32885 positions = this.getVerticalTwoBoxColPositions(x, y, box);
32888 positions = this.getVerticalThreeBoxColPositions(x, y, box);
32891 positions = this.getVerticalFourBoxColPositions(x, y, box);
32897 Roo.each(box, function(b,kk){
32899 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
32901 var sz = b.el.getSize();
32903 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
32911 for (var i = 0; i < this.cols; i++){
32912 mY = Math.max(mY, maxY[i]);
32915 this.el.setHeight(mY - pos.y);
32919 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
32921 // var pos = this.el.getBox(true);
32924 // var maxX = pos.right;
32926 // var maxHeight = 0;
32928 // Roo.each(items, function(item, k){
32932 // item.el.position('absolute');
32934 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
32936 // item.el.setWidth(width);
32938 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
32940 // item.el.setHeight(height);
32943 // item.el.setXY([x, y], isInstant ? false : true);
32945 // item.el.setXY([maxX - width, y], isInstant ? false : true);
32948 // y = y + height + this.alternativePadWidth;
32950 // maxHeight = maxHeight + height + this.alternativePadWidth;
32954 // this.el.setHeight(maxHeight);
32958 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
32960 var pos = this.el.getBox(true);
32965 var maxX = pos.right;
32967 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
32969 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
32971 Roo.each(queue, function(box, k){
32973 Roo.each(box, function(b, kk){
32975 b.el.position('absolute');
32977 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32978 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32980 if(b.size == 'md-left' || b.size == 'md-right'){
32981 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
32982 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32985 b.el.setWidth(width);
32986 b.el.setHeight(height);
32994 var positions = [];
32996 switch (box.length){
32998 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
33001 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
33004 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
33007 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
33013 Roo.each(box, function(b,kk){
33015 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33017 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
33025 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
33027 Roo.each(eItems, function(b,k){
33029 b.size = (k == 0) ? 'sm' : 'xs';
33030 b.x = (k == 0) ? 2 : 1;
33031 b.y = (k == 0) ? 2 : 1;
33033 b.el.position('absolute');
33035 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33037 b.el.setWidth(width);
33039 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33041 b.el.setHeight(height);
33045 var positions = [];
33048 x : maxX - this.unitWidth * 2 - this.gutter,
33053 x : maxX - this.unitWidth,
33054 y : minY + (this.unitWidth + this.gutter) * 2
33058 x : maxX - this.unitWidth * 3 - this.gutter * 2,
33062 Roo.each(eItems, function(b,k){
33064 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
33070 getVerticalOneBoxColPositions : function(x, y, box)
33074 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
33076 if(box[0].size == 'md-left'){
33080 if(box[0].size == 'md-right'){
33085 x : x + (this.unitWidth + this.gutter) * rand,
33092 getVerticalTwoBoxColPositions : function(x, y, box)
33096 if(box[0].size == 'xs'){
33100 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
33104 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
33118 x : x + (this.unitWidth + this.gutter) * 2,
33119 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
33126 getVerticalThreeBoxColPositions : function(x, y, box)
33130 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
33138 x : x + (this.unitWidth + this.gutter) * 1,
33143 x : x + (this.unitWidth + this.gutter) * 2,
33151 if(box[0].size == 'xs' && box[1].size == 'xs'){
33160 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
33164 x : x + (this.unitWidth + this.gutter) * 1,
33178 x : x + (this.unitWidth + this.gutter) * 2,
33183 x : x + (this.unitWidth + this.gutter) * 2,
33184 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
33191 getVerticalFourBoxColPositions : function(x, y, box)
33195 if(box[0].size == 'xs'){
33204 y : y + (this.unitHeight + this.gutter) * 1
33209 y : y + (this.unitHeight + this.gutter) * 2
33213 x : x + (this.unitWidth + this.gutter) * 1,
33227 x : x + (this.unitWidth + this.gutter) * 2,
33232 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
33233 y : y + (this.unitHeight + this.gutter) * 1
33237 x : x + (this.unitWidth + this.gutter) * 2,
33238 y : y + (this.unitWidth + this.gutter) * 2
33245 getHorizontalOneBoxColPositions : function(maxX, minY, box)
33249 if(box[0].size == 'md-left'){
33251 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
33258 if(box[0].size == 'md-right'){
33260 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
33261 y : minY + (this.unitWidth + this.gutter) * 1
33267 var rand = Math.floor(Math.random() * (4 - box[0].y));
33270 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33271 y : minY + (this.unitWidth + this.gutter) * rand
33278 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
33282 if(box[0].size == 'xs'){
33285 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33290 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33291 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
33299 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33304 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33305 y : minY + (this.unitWidth + this.gutter) * 2
33312 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
33316 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
33319 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33324 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33325 y : minY + (this.unitWidth + this.gutter) * 1
33329 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33330 y : minY + (this.unitWidth + this.gutter) * 2
33337 if(box[0].size == 'xs' && box[1].size == 'xs'){
33340 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33345 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33350 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33351 y : minY + (this.unitWidth + this.gutter) * 1
33359 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33364 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33365 y : minY + (this.unitWidth + this.gutter) * 2
33369 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33370 y : minY + (this.unitWidth + this.gutter) * 2
33377 getHorizontalFourBoxColPositions : function(maxX, minY, box)
33381 if(box[0].size == 'xs'){
33384 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33389 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33394 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),
33399 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
33400 y : minY + (this.unitWidth + this.gutter) * 1
33408 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33413 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33414 y : minY + (this.unitWidth + this.gutter) * 2
33418 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33419 y : minY + (this.unitWidth + this.gutter) * 2
33423 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),
33424 y : minY + (this.unitWidth + this.gutter) * 2
33432 * remove a Masonry Brick
33433 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
33435 removeBrick : function(brick_id)
33441 for (var i = 0; i<this.bricks.length; i++) {
33442 if (this.bricks[i].id == brick_id) {
33443 this.bricks.splice(i,1);
33444 this.el.dom.removeChild(Roo.get(brick_id).dom);
33451 * adds a Masonry Brick
33452 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33454 addBrick : function(cfg)
33456 var cn = new Roo.bootstrap.MasonryBrick(cfg);
33457 //this.register(cn);
33458 cn.parentId = this.id;
33459 cn.render(this.el);
33464 * register a Masonry Brick
33465 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33468 register : function(brick)
33470 this.bricks.push(brick);
33471 brick.masonryId = this.id;
33475 * clear all the Masonry Brick
33477 clearAll : function()
33480 //this.getChildContainer().dom.innerHTML = "";
33481 this.el.dom.innerHTML = '';
33484 getSelected : function()
33486 if (!this.selectedBrick) {
33490 return this.selectedBrick;
33494 Roo.apply(Roo.bootstrap.LayoutMasonry, {
33498 * register a Masonry Layout
33499 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
33502 register : function(layout)
33504 this.groups[layout.id] = layout;
33507 * fetch a Masonry Layout based on the masonry layout ID
33508 * @param {string} the masonry layout to add
33509 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
33512 get: function(layout_id) {
33513 if (typeof(this.groups[layout_id]) == 'undefined') {
33516 return this.groups[layout_id] ;
33528 * http://masonry.desandro.com
33530 * The idea is to render all the bricks based on vertical width...
33532 * The original code extends 'outlayer' - we might need to use that....
33538 * @class Roo.bootstrap.LayoutMasonryAuto
33539 * @extends Roo.bootstrap.Component
33540 * Bootstrap Layout Masonry class
33543 * Create a new Element
33544 * @param {Object} config The config object
33547 Roo.bootstrap.LayoutMasonryAuto = function(config){
33548 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
33551 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
33554 * @cfg {Boolean} isFitWidth - resize the width..
33556 isFitWidth : false, // options..
33558 * @cfg {Boolean} isOriginLeft = left align?
33560 isOriginLeft : true,
33562 * @cfg {Boolean} isOriginTop = top align?
33564 isOriginTop : false,
33566 * @cfg {Boolean} isLayoutInstant = no animation?
33568 isLayoutInstant : false, // needed?
33570 * @cfg {Boolean} isResizingContainer = not sure if this is used..
33572 isResizingContainer : true,
33574 * @cfg {Number} columnWidth width of the columns
33580 * @cfg {Number} maxCols maximum number of columns
33585 * @cfg {Number} padHeight padding below box..
33591 * @cfg {Boolean} isAutoInitial defalut true
33594 isAutoInitial : true,
33600 initialColumnWidth : 0,
33601 currentSize : null,
33603 colYs : null, // array.
33610 bricks: null, //CompositeElement
33611 cols : 0, // array?
33612 // element : null, // wrapped now this.el
33613 _isLayoutInited : null,
33616 getAutoCreate : function(){
33620 cls: 'blog-masonary-wrapper ' + this.cls,
33622 cls : 'mas-boxes masonary'
33629 getChildContainer: function( )
33631 if (this.boxesEl) {
33632 return this.boxesEl;
33635 this.boxesEl = this.el.select('.mas-boxes').first();
33637 return this.boxesEl;
33641 initEvents : function()
33645 if(this.isAutoInitial){
33646 Roo.log('hook children rendered');
33647 this.on('childrenrendered', function() {
33648 Roo.log('children rendered');
33655 initial : function()
33657 this.reloadItems();
33659 this.currentSize = this.el.getBox(true);
33661 /// was window resize... - let's see if this works..
33662 Roo.EventManager.onWindowResize(this.resize, this);
33664 if(!this.isAutoInitial){
33669 this.layout.defer(500,this);
33672 reloadItems: function()
33674 this.bricks = this.el.select('.masonry-brick', true);
33676 this.bricks.each(function(b) {
33677 //Roo.log(b.getSize());
33678 if (!b.attr('originalwidth')) {
33679 b.attr('originalwidth', b.getSize().width);
33684 Roo.log(this.bricks.elements.length);
33687 resize : function()
33690 var cs = this.el.getBox(true);
33692 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
33693 Roo.log("no change in with or X");
33696 this.currentSize = cs;
33700 layout : function()
33703 this._resetLayout();
33704 //this._manageStamps();
33706 // don't animate first layout
33707 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
33708 this.layoutItems( isInstant );
33710 // flag for initalized
33711 this._isLayoutInited = true;
33714 layoutItems : function( isInstant )
33716 //var items = this._getItemsForLayout( this.items );
33717 // original code supports filtering layout items.. we just ignore it..
33719 this._layoutItems( this.bricks , isInstant );
33721 this._postLayout();
33723 _layoutItems : function ( items , isInstant)
33725 //this.fireEvent( 'layout', this, items );
33728 if ( !items || !items.elements.length ) {
33729 // no items, emit event with empty array
33734 items.each(function(item) {
33735 Roo.log("layout item");
33737 // get x/y object from method
33738 var position = this._getItemLayoutPosition( item );
33740 position.item = item;
33741 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
33742 queue.push( position );
33745 this._processLayoutQueue( queue );
33747 /** Sets position of item in DOM
33748 * @param {Element} item
33749 * @param {Number} x - horizontal position
33750 * @param {Number} y - vertical position
33751 * @param {Boolean} isInstant - disables transitions
33753 _processLayoutQueue : function( queue )
33755 for ( var i=0, len = queue.length; i < len; i++ ) {
33756 var obj = queue[i];
33757 obj.item.position('absolute');
33758 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
33764 * Any logic you want to do after each layout,
33765 * i.e. size the container
33767 _postLayout : function()
33769 this.resizeContainer();
33772 resizeContainer : function()
33774 if ( !this.isResizingContainer ) {
33777 var size = this._getContainerSize();
33779 this.el.setSize(size.width,size.height);
33780 this.boxesEl.setSize(size.width,size.height);
33786 _resetLayout : function()
33788 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
33789 this.colWidth = this.el.getWidth();
33790 //this.gutter = this.el.getWidth();
33792 this.measureColumns();
33798 this.colYs.push( 0 );
33804 measureColumns : function()
33806 this.getContainerWidth();
33807 // if columnWidth is 0, default to outerWidth of first item
33808 if ( !this.columnWidth ) {
33809 var firstItem = this.bricks.first();
33810 Roo.log(firstItem);
33811 this.columnWidth = this.containerWidth;
33812 if (firstItem && firstItem.attr('originalwidth') ) {
33813 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
33815 // columnWidth fall back to item of first element
33816 Roo.log("set column width?");
33817 this.initialColumnWidth = this.columnWidth ;
33819 // if first elem has no width, default to size of container
33824 if (this.initialColumnWidth) {
33825 this.columnWidth = this.initialColumnWidth;
33830 // column width is fixed at the top - however if container width get's smaller we should
33833 // this bit calcs how man columns..
33835 var columnWidth = this.columnWidth += this.gutter;
33837 // calculate columns
33838 var containerWidth = this.containerWidth + this.gutter;
33840 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
33841 // fix rounding errors, typically with gutters
33842 var excess = columnWidth - containerWidth % columnWidth;
33845 // if overshoot is less than a pixel, round up, otherwise floor it
33846 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
33847 cols = Math[ mathMethod ]( cols );
33848 this.cols = Math.max( cols, 1 );
33849 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
33851 // padding positioning..
33852 var totalColWidth = this.cols * this.columnWidth;
33853 var padavail = this.containerWidth - totalColWidth;
33854 // so for 2 columns - we need 3 'pads'
33856 var padNeeded = (1+this.cols) * this.padWidth;
33858 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
33860 this.columnWidth += padExtra
33861 //this.padWidth = Math.floor(padavail / ( this.cols));
33863 // adjust colum width so that padding is fixed??
33865 // we have 3 columns ... total = width * 3
33866 // we have X left over... that should be used by
33868 //if (this.expandC) {
33876 getContainerWidth : function()
33878 /* // container is parent if fit width
33879 var container = this.isFitWidth ? this.element.parentNode : this.element;
33880 // check that this.size and size are there
33881 // IE8 triggers resize on body size change, so they might not be
33883 var size = getSize( container ); //FIXME
33884 this.containerWidth = size && size.innerWidth; //FIXME
33887 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
33891 _getItemLayoutPosition : function( item ) // what is item?
33893 // we resize the item to our columnWidth..
33895 item.setWidth(this.columnWidth);
33896 item.autoBoxAdjust = false;
33898 var sz = item.getSize();
33900 // how many columns does this brick span
33901 var remainder = this.containerWidth % this.columnWidth;
33903 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
33904 // round if off by 1 pixel, otherwise use ceil
33905 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
33906 colSpan = Math.min( colSpan, this.cols );
33908 // normally this should be '1' as we dont' currently allow multi width columns..
33910 var colGroup = this._getColGroup( colSpan );
33911 // get the minimum Y value from the columns
33912 var minimumY = Math.min.apply( Math, colGroup );
33913 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
33915 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
33917 // position the brick
33919 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
33920 y: this.currentSize.y + minimumY + this.padHeight
33924 // apply setHeight to necessary columns
33925 var setHeight = minimumY + sz.height + this.padHeight;
33926 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
33928 var setSpan = this.cols + 1 - colGroup.length;
33929 for ( var i = 0; i < setSpan; i++ ) {
33930 this.colYs[ shortColIndex + i ] = setHeight ;
33937 * @param {Number} colSpan - number of columns the element spans
33938 * @returns {Array} colGroup
33940 _getColGroup : function( colSpan )
33942 if ( colSpan < 2 ) {
33943 // if brick spans only one column, use all the column Ys
33948 // how many different places could this brick fit horizontally
33949 var groupCount = this.cols + 1 - colSpan;
33950 // for each group potential horizontal position
33951 for ( var i = 0; i < groupCount; i++ ) {
33952 // make an array of colY values for that one group
33953 var groupColYs = this.colYs.slice( i, i + colSpan );
33954 // and get the max value of the array
33955 colGroup[i] = Math.max.apply( Math, groupColYs );
33960 _manageStamp : function( stamp )
33962 var stampSize = stamp.getSize();
33963 var offset = stamp.getBox();
33964 // get the columns that this stamp affects
33965 var firstX = this.isOriginLeft ? offset.x : offset.right;
33966 var lastX = firstX + stampSize.width;
33967 var firstCol = Math.floor( firstX / this.columnWidth );
33968 firstCol = Math.max( 0, firstCol );
33970 var lastCol = Math.floor( lastX / this.columnWidth );
33971 // lastCol should not go over if multiple of columnWidth #425
33972 lastCol -= lastX % this.columnWidth ? 0 : 1;
33973 lastCol = Math.min( this.cols - 1, lastCol );
33975 // set colYs to bottom of the stamp
33976 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
33979 for ( var i = firstCol; i <= lastCol; i++ ) {
33980 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
33985 _getContainerSize : function()
33987 this.maxY = Math.max.apply( Math, this.colYs );
33992 if ( this.isFitWidth ) {
33993 size.width = this._getContainerFitWidth();
33999 _getContainerFitWidth : function()
34001 var unusedCols = 0;
34002 // count unused columns
34005 if ( this.colYs[i] !== 0 ) {
34010 // fit container to columns that have been used
34011 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
34014 needsResizeLayout : function()
34016 var previousWidth = this.containerWidth;
34017 this.getContainerWidth();
34018 return previousWidth !== this.containerWidth;
34033 * @class Roo.bootstrap.MasonryBrick
34034 * @extends Roo.bootstrap.Component
34035 * Bootstrap MasonryBrick class
34038 * Create a new MasonryBrick
34039 * @param {Object} config The config object
34042 Roo.bootstrap.MasonryBrick = function(config){
34044 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
34046 Roo.bootstrap.MasonryBrick.register(this);
34052 * When a MasonryBrick is clcik
34053 * @param {Roo.bootstrap.MasonryBrick} this
34054 * @param {Roo.EventObject} e
34060 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
34063 * @cfg {String} title
34067 * @cfg {String} html
34071 * @cfg {String} bgimage
34075 * @cfg {String} videourl
34079 * @cfg {String} cls
34083 * @cfg {String} href
34087 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
34092 * @cfg {String} placetitle (center|bottom)
34097 * @cfg {Boolean} isFitContainer defalut true
34099 isFitContainer : true,
34102 * @cfg {Boolean} preventDefault defalut false
34104 preventDefault : false,
34107 * @cfg {Boolean} inverse defalut false
34109 maskInverse : false,
34111 getAutoCreate : function()
34113 if(!this.isFitContainer){
34114 return this.getSplitAutoCreate();
34117 var cls = 'masonry-brick masonry-brick-full';
34119 if(this.href.length){
34120 cls += ' masonry-brick-link';
34123 if(this.bgimage.length){
34124 cls += ' masonry-brick-image';
34127 if(this.maskInverse){
34128 cls += ' mask-inverse';
34131 if(!this.html.length && !this.maskInverse && !this.videourl.length){
34132 cls += ' enable-mask';
34136 cls += ' masonry-' + this.size + '-brick';
34139 if(this.placetitle.length){
34141 switch (this.placetitle) {
34143 cls += ' masonry-center-title';
34146 cls += ' masonry-bottom-title';
34153 if(!this.html.length && !this.bgimage.length){
34154 cls += ' masonry-center-title';
34157 if(!this.html.length && this.bgimage.length){
34158 cls += ' masonry-bottom-title';
34163 cls += ' ' + this.cls;
34167 tag: (this.href.length) ? 'a' : 'div',
34172 cls: 'masonry-brick-mask'
34176 cls: 'masonry-brick-paragraph',
34182 if(this.href.length){
34183 cfg.href = this.href;
34186 var cn = cfg.cn[1].cn;
34188 if(this.title.length){
34191 cls: 'masonry-brick-title',
34196 if(this.html.length){
34199 cls: 'masonry-brick-text',
34204 if (!this.title.length && !this.html.length) {
34205 cfg.cn[1].cls += ' hide';
34208 if(this.bgimage.length){
34211 cls: 'masonry-brick-image-view',
34216 if(this.videourl.length){
34217 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
34218 // youtube support only?
34221 cls: 'masonry-brick-image-view',
34224 allowfullscreen : true
34232 getSplitAutoCreate : function()
34234 var cls = 'masonry-brick masonry-brick-split';
34236 if(this.href.length){
34237 cls += ' masonry-brick-link';
34240 if(this.bgimage.length){
34241 cls += ' masonry-brick-image';
34245 cls += ' masonry-' + this.size + '-brick';
34248 switch (this.placetitle) {
34250 cls += ' masonry-center-title';
34253 cls += ' masonry-bottom-title';
34256 if(!this.bgimage.length){
34257 cls += ' masonry-center-title';
34260 if(this.bgimage.length){
34261 cls += ' masonry-bottom-title';
34267 cls += ' ' + this.cls;
34271 tag: (this.href.length) ? 'a' : 'div',
34276 cls: 'masonry-brick-split-head',
34280 cls: 'masonry-brick-paragraph',
34287 cls: 'masonry-brick-split-body',
34293 if(this.href.length){
34294 cfg.href = this.href;
34297 if(this.title.length){
34298 cfg.cn[0].cn[0].cn.push({
34300 cls: 'masonry-brick-title',
34305 if(this.html.length){
34306 cfg.cn[1].cn.push({
34308 cls: 'masonry-brick-text',
34313 if(this.bgimage.length){
34314 cfg.cn[0].cn.push({
34316 cls: 'masonry-brick-image-view',
34321 if(this.videourl.length){
34322 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
34323 // youtube support only?
34324 cfg.cn[0].cn.cn.push({
34326 cls: 'masonry-brick-image-view',
34329 allowfullscreen : true
34336 initEvents: function()
34338 switch (this.size) {
34371 this.el.on('touchstart', this.onTouchStart, this);
34372 this.el.on('touchmove', this.onTouchMove, this);
34373 this.el.on('touchend', this.onTouchEnd, this);
34374 this.el.on('contextmenu', this.onContextMenu, this);
34376 this.el.on('mouseenter' ,this.enter, this);
34377 this.el.on('mouseleave', this.leave, this);
34378 this.el.on('click', this.onClick, this);
34381 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
34382 this.parent().bricks.push(this);
34387 onClick: function(e, el)
34389 var time = this.endTimer - this.startTimer;
34390 // Roo.log(e.preventDefault());
34393 e.preventDefault();
34398 if(!this.preventDefault){
34402 e.preventDefault();
34404 if (this.activeClass != '') {
34405 this.selectBrick();
34408 this.fireEvent('click', this, e);
34411 enter: function(e, el)
34413 e.preventDefault();
34415 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
34419 if(this.bgimage.length && this.html.length){
34420 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
34424 leave: function(e, el)
34426 e.preventDefault();
34428 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
34432 if(this.bgimage.length && this.html.length){
34433 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
34437 onTouchStart: function(e, el)
34439 // e.preventDefault();
34441 this.touchmoved = false;
34443 if(!this.isFitContainer){
34447 if(!this.bgimage.length || !this.html.length){
34451 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
34453 this.timer = new Date().getTime();
34457 onTouchMove: function(e, el)
34459 this.touchmoved = true;
34462 onContextMenu : function(e,el)
34464 e.preventDefault();
34465 e.stopPropagation();
34469 onTouchEnd: function(e, el)
34471 // e.preventDefault();
34473 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
34480 if(!this.bgimage.length || !this.html.length){
34482 if(this.href.length){
34483 window.location.href = this.href;
34489 if(!this.isFitContainer){
34493 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
34495 window.location.href = this.href;
34498 //selection on single brick only
34499 selectBrick : function() {
34501 if (!this.parentId) {
34505 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
34506 var index = m.selectedBrick.indexOf(this.id);
34509 m.selectedBrick.splice(index,1);
34510 this.el.removeClass(this.activeClass);
34514 for(var i = 0; i < m.selectedBrick.length; i++) {
34515 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
34516 b.el.removeClass(b.activeClass);
34519 m.selectedBrick = [];
34521 m.selectedBrick.push(this.id);
34522 this.el.addClass(this.activeClass);
34526 isSelected : function(){
34527 return this.el.hasClass(this.activeClass);
34532 Roo.apply(Roo.bootstrap.MasonryBrick, {
34535 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
34537 * register a Masonry Brick
34538 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34541 register : function(brick)
34543 //this.groups[brick.id] = brick;
34544 this.groups.add(brick.id, brick);
34547 * fetch a masonry brick based on the masonry brick ID
34548 * @param {string} the masonry brick to add
34549 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
34552 get: function(brick_id)
34554 // if (typeof(this.groups[brick_id]) == 'undefined') {
34557 // return this.groups[brick_id] ;
34559 if(this.groups.key(brick_id)) {
34560 return this.groups.key(brick_id);
34578 * @class Roo.bootstrap.Brick
34579 * @extends Roo.bootstrap.Component
34580 * Bootstrap Brick class
34583 * Create a new Brick
34584 * @param {Object} config The config object
34587 Roo.bootstrap.Brick = function(config){
34588 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
34594 * When a Brick is click
34595 * @param {Roo.bootstrap.Brick} this
34596 * @param {Roo.EventObject} e
34602 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
34605 * @cfg {String} title
34609 * @cfg {String} html
34613 * @cfg {String} bgimage
34617 * @cfg {String} cls
34621 * @cfg {String} href
34625 * @cfg {String} video
34629 * @cfg {Boolean} square
34633 getAutoCreate : function()
34635 var cls = 'roo-brick';
34637 if(this.href.length){
34638 cls += ' roo-brick-link';
34641 if(this.bgimage.length){
34642 cls += ' roo-brick-image';
34645 if(!this.html.length && !this.bgimage.length){
34646 cls += ' roo-brick-center-title';
34649 if(!this.html.length && this.bgimage.length){
34650 cls += ' roo-brick-bottom-title';
34654 cls += ' ' + this.cls;
34658 tag: (this.href.length) ? 'a' : 'div',
34663 cls: 'roo-brick-paragraph',
34669 if(this.href.length){
34670 cfg.href = this.href;
34673 var cn = cfg.cn[0].cn;
34675 if(this.title.length){
34678 cls: 'roo-brick-title',
34683 if(this.html.length){
34686 cls: 'roo-brick-text',
34693 if(this.bgimage.length){
34696 cls: 'roo-brick-image-view',
34704 initEvents: function()
34706 if(this.title.length || this.html.length){
34707 this.el.on('mouseenter' ,this.enter, this);
34708 this.el.on('mouseleave', this.leave, this);
34711 Roo.EventManager.onWindowResize(this.resize, this);
34713 if(this.bgimage.length){
34714 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
34715 this.imageEl.on('load', this.onImageLoad, this);
34722 onImageLoad : function()
34727 resize : function()
34729 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
34731 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
34733 if(this.bgimage.length){
34734 var image = this.el.select('.roo-brick-image-view', true).first();
34736 image.setWidth(paragraph.getWidth());
34739 image.setHeight(paragraph.getWidth());
34742 this.el.setHeight(image.getHeight());
34743 paragraph.setHeight(image.getHeight());
34749 enter: function(e, el)
34751 e.preventDefault();
34753 if(this.bgimage.length){
34754 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
34755 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
34759 leave: function(e, el)
34761 e.preventDefault();
34763 if(this.bgimage.length){
34764 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
34765 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
34780 * @class Roo.bootstrap.NumberField
34781 * @extends Roo.bootstrap.Input
34782 * Bootstrap NumberField class
34788 * Create a new NumberField
34789 * @param {Object} config The config object
34792 Roo.bootstrap.NumberField = function(config){
34793 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
34796 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
34799 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
34801 allowDecimals : true,
34803 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
34805 decimalSeparator : ".",
34807 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
34809 decimalPrecision : 2,
34811 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
34813 allowNegative : true,
34816 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
34820 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
34822 minValue : Number.NEGATIVE_INFINITY,
34824 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
34826 maxValue : Number.MAX_VALUE,
34828 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
34830 minText : "The minimum value for this field is {0}",
34832 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
34834 maxText : "The maximum value for this field is {0}",
34836 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
34837 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
34839 nanText : "{0} is not a valid number",
34841 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
34843 thousandsDelimiter : false,
34845 * @cfg {String} valueAlign alignment of value
34847 valueAlign : "left",
34849 getAutoCreate : function()
34851 var hiddenInput = {
34855 cls: 'hidden-number-input'
34859 hiddenInput.name = this.name;
34864 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
34866 this.name = hiddenInput.name;
34868 if(cfg.cn.length > 0) {
34869 cfg.cn.push(hiddenInput);
34876 initEvents : function()
34878 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
34880 var allowed = "0123456789";
34882 if(this.allowDecimals){
34883 allowed += this.decimalSeparator;
34886 if(this.allowNegative){
34890 if(this.thousandsDelimiter) {
34894 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
34896 var keyPress = function(e){
34898 var k = e.getKey();
34900 var c = e.getCharCode();
34903 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
34904 allowed.indexOf(String.fromCharCode(c)) === -1
34910 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
34914 if(allowed.indexOf(String.fromCharCode(c)) === -1){
34919 this.el.on("keypress", keyPress, this);
34922 validateValue : function(value)
34925 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
34929 var num = this.parseValue(value);
34932 this.markInvalid(String.format(this.nanText, value));
34936 if(num < this.minValue){
34937 this.markInvalid(String.format(this.minText, this.minValue));
34941 if(num > this.maxValue){
34942 this.markInvalid(String.format(this.maxText, this.maxValue));
34949 getValue : function()
34951 var v = this.hiddenEl().getValue();
34953 return this.fixPrecision(this.parseValue(v));
34956 parseValue : function(value)
34958 if(this.thousandsDelimiter) {
34960 r = new RegExp(",", "g");
34961 value = value.replace(r, "");
34964 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
34965 return isNaN(value) ? '' : value;
34968 fixPrecision : function(value)
34970 if(this.thousandsDelimiter) {
34972 r = new RegExp(",", "g");
34973 value = value.replace(r, "");
34976 var nan = isNaN(value);
34978 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
34979 return nan ? '' : value;
34981 return parseFloat(value).toFixed(this.decimalPrecision);
34984 setValue : function(v)
34986 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
34992 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
34994 this.inputEl().dom.value = (v == '') ? '' :
34995 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
34997 if(!this.allowZero && v === '0') {
34998 this.hiddenEl().dom.value = '';
34999 this.inputEl().dom.value = '';
35006 decimalPrecisionFcn : function(v)
35008 return Math.floor(v);
35011 beforeBlur : function()
35013 var v = this.parseValue(this.getRawValue());
35015 if(v || v === 0 || v === ''){
35020 hiddenEl : function()
35022 return this.el.select('input.hidden-number-input',true).first();
35034 * @class Roo.bootstrap.DocumentSlider
35035 * @extends Roo.bootstrap.Component
35036 * Bootstrap DocumentSlider class
35039 * Create a new DocumentViewer
35040 * @param {Object} config The config object
35043 Roo.bootstrap.DocumentSlider = function(config){
35044 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
35051 * Fire after initEvent
35052 * @param {Roo.bootstrap.DocumentSlider} this
35057 * Fire after update
35058 * @param {Roo.bootstrap.DocumentSlider} this
35064 * @param {Roo.bootstrap.DocumentSlider} this
35070 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
35076 getAutoCreate : function()
35080 cls : 'roo-document-slider',
35084 cls : 'roo-document-slider-header',
35088 cls : 'roo-document-slider-header-title'
35094 cls : 'roo-document-slider-body',
35098 cls : 'roo-document-slider-prev',
35102 cls : 'fa fa-chevron-left'
35108 cls : 'roo-document-slider-thumb',
35112 cls : 'roo-document-slider-image'
35118 cls : 'roo-document-slider-next',
35122 cls : 'fa fa-chevron-right'
35134 initEvents : function()
35136 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
35137 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
35139 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
35140 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
35142 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
35143 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
35145 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
35146 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
35148 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
35149 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
35151 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
35152 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35154 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
35155 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35157 this.thumbEl.on('click', this.onClick, this);
35159 this.prevIndicator.on('click', this.prev, this);
35161 this.nextIndicator.on('click', this.next, this);
35165 initial : function()
35167 if(this.files.length){
35168 this.indicator = 1;
35172 this.fireEvent('initial', this);
35175 update : function()
35177 this.imageEl.attr('src', this.files[this.indicator - 1]);
35179 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
35181 this.prevIndicator.show();
35183 if(this.indicator == 1){
35184 this.prevIndicator.hide();
35187 this.nextIndicator.show();
35189 if(this.indicator == this.files.length){
35190 this.nextIndicator.hide();
35193 this.thumbEl.scrollTo('top');
35195 this.fireEvent('update', this);
35198 onClick : function(e)
35200 e.preventDefault();
35202 this.fireEvent('click', this);
35207 e.preventDefault();
35209 this.indicator = Math.max(1, this.indicator - 1);
35216 e.preventDefault();
35218 this.indicator = Math.min(this.files.length, this.indicator + 1);
35232 * @class Roo.bootstrap.RadioSet
35233 * @extends Roo.bootstrap.Input
35234 * Bootstrap RadioSet class
35235 * @cfg {String} indicatorpos (left|right) default left
35236 * @cfg {Boolean} inline (true|false) inline the element (default true)
35237 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
35239 * Create a new RadioSet
35240 * @param {Object} config The config object
35243 Roo.bootstrap.RadioSet = function(config){
35245 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
35249 Roo.bootstrap.RadioSet.register(this);
35254 * Fires when the element is checked or unchecked.
35255 * @param {Roo.bootstrap.RadioSet} this This radio
35256 * @param {Roo.bootstrap.Radio} item The checked item
35261 * Fires when the element is click.
35262 * @param {Roo.bootstrap.RadioSet} this This radio set
35263 * @param {Roo.bootstrap.Radio} item The checked item
35264 * @param {Roo.EventObject} e The event object
35271 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
35279 indicatorpos : 'left',
35281 getAutoCreate : function()
35285 cls : 'roo-radio-set-label',
35289 html : this.fieldLabel
35293 if (Roo.bootstrap.version == 3) {
35296 if(this.indicatorpos == 'left'){
35299 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
35300 tooltip : 'This field is required'
35305 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
35306 tooltip : 'This field is required'
35312 cls : 'roo-radio-set-items'
35315 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
35317 if (align === 'left' && this.fieldLabel.length) {
35320 cls : "roo-radio-set-right",
35326 if(this.labelWidth > 12){
35327 label.style = "width: " + this.labelWidth + 'px';
35330 if(this.labelWidth < 13 && this.labelmd == 0){
35331 this.labelmd = this.labelWidth;
35334 if(this.labellg > 0){
35335 label.cls += ' col-lg-' + this.labellg;
35336 items.cls += ' col-lg-' + (12 - this.labellg);
35339 if(this.labelmd > 0){
35340 label.cls += ' col-md-' + this.labelmd;
35341 items.cls += ' col-md-' + (12 - this.labelmd);
35344 if(this.labelsm > 0){
35345 label.cls += ' col-sm-' + this.labelsm;
35346 items.cls += ' col-sm-' + (12 - this.labelsm);
35349 if(this.labelxs > 0){
35350 label.cls += ' col-xs-' + this.labelxs;
35351 items.cls += ' col-xs-' + (12 - this.labelxs);
35357 cls : 'roo-radio-set',
35361 cls : 'roo-radio-set-input',
35364 value : this.value ? this.value : ''
35371 if(this.weight.length){
35372 cfg.cls += ' roo-radio-' + this.weight;
35376 cfg.cls += ' roo-radio-set-inline';
35380 ['xs','sm','md','lg'].map(function(size){
35381 if (settings[size]) {
35382 cfg.cls += ' col-' + size + '-' + settings[size];
35390 initEvents : function()
35392 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
35393 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
35395 if(!this.fieldLabel.length){
35396 this.labelEl.hide();
35399 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
35400 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
35402 this.indicator = this.indicatorEl();
35404 if(this.indicator){
35405 this.indicator.addClass('invisible');
35408 this.originalValue = this.getValue();
35412 inputEl: function ()
35414 return this.el.select('.roo-radio-set-input', true).first();
35417 getChildContainer : function()
35419 return this.itemsEl;
35422 register : function(item)
35424 this.radioes.push(item);
35428 validate : function()
35430 if(this.getVisibilityEl().hasClass('hidden')){
35436 Roo.each(this.radioes, function(i){
35445 if(this.allowBlank) {
35449 if(this.disabled || valid){
35454 this.markInvalid();
35459 markValid : function()
35461 if(this.labelEl.isVisible(true) && this.indicatorEl()){
35462 this.indicatorEl().removeClass('visible');
35463 this.indicatorEl().addClass('invisible');
35467 if (Roo.bootstrap.version == 3) {
35468 this.el.removeClass([this.invalidClass, this.validClass]);
35469 this.el.addClass(this.validClass);
35471 this.el.removeClass(['is-invalid','is-valid']);
35472 this.el.addClass(['is-valid']);
35474 this.fireEvent('valid', this);
35477 markInvalid : function(msg)
35479 if(this.allowBlank || this.disabled){
35483 if(this.labelEl.isVisible(true) && this.indicatorEl()){
35484 this.indicatorEl().removeClass('invisible');
35485 this.indicatorEl().addClass('visible');
35487 if (Roo.bootstrap.version == 3) {
35488 this.el.removeClass([this.invalidClass, this.validClass]);
35489 this.el.addClass(this.invalidClass);
35491 this.el.removeClass(['is-invalid','is-valid']);
35492 this.el.addClass(['is-invalid']);
35495 this.fireEvent('invalid', this, msg);
35499 setValue : function(v, suppressEvent)
35501 if(this.value === v){
35508 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
35511 Roo.each(this.radioes, function(i){
35513 i.el.removeClass('checked');
35516 Roo.each(this.radioes, function(i){
35518 if(i.value === v || i.value.toString() === v.toString()){
35520 i.el.addClass('checked');
35522 if(suppressEvent !== true){
35523 this.fireEvent('check', this, i);
35534 clearInvalid : function(){
35536 if(!this.el || this.preventMark){
35540 this.el.removeClass([this.invalidClass]);
35542 this.fireEvent('valid', this);
35547 Roo.apply(Roo.bootstrap.RadioSet, {
35551 register : function(set)
35553 this.groups[set.name] = set;
35556 get: function(name)
35558 if (typeof(this.groups[name]) == 'undefined') {
35562 return this.groups[name] ;
35568 * Ext JS Library 1.1.1
35569 * Copyright(c) 2006-2007, Ext JS, LLC.
35571 * Originally Released Under LGPL - original licence link has changed is not relivant.
35574 * <script type="text/javascript">
35579 * @class Roo.bootstrap.SplitBar
35580 * @extends Roo.util.Observable
35581 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
35585 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
35586 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
35587 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
35588 split.minSize = 100;
35589 split.maxSize = 600;
35590 split.animate = true;
35591 split.on('moved', splitterMoved);
35594 * Create a new SplitBar
35595 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
35596 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
35597 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
35598 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
35599 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
35600 position of the SplitBar).
35602 Roo.bootstrap.SplitBar = function(cfg){
35607 // dragElement : elm
35608 // resizingElement: el,
35610 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
35611 // placement : Roo.bootstrap.SplitBar.LEFT ,
35612 // existingProxy ???
35615 this.el = Roo.get(cfg.dragElement, true);
35616 this.el.dom.unselectable = "on";
35618 this.resizingEl = Roo.get(cfg.resizingElement, true);
35622 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
35623 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
35626 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
35629 * The minimum size of the resizing element. (Defaults to 0)
35635 * The maximum size of the resizing element. (Defaults to 2000)
35638 this.maxSize = 2000;
35641 * Whether to animate the transition to the new size
35644 this.animate = false;
35647 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
35650 this.useShim = false;
35655 if(!cfg.existingProxy){
35657 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
35659 this.proxy = Roo.get(cfg.existingProxy).dom;
35662 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
35665 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
35668 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
35671 this.dragSpecs = {};
35674 * @private The adapter to use to positon and resize elements
35676 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
35677 this.adapter.init(this);
35679 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35681 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
35682 this.el.addClass("roo-splitbar-h");
35685 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
35686 this.el.addClass("roo-splitbar-v");
35692 * Fires when the splitter is moved (alias for {@link #event-moved})
35693 * @param {Roo.bootstrap.SplitBar} this
35694 * @param {Number} newSize the new width or height
35699 * Fires when the splitter is moved
35700 * @param {Roo.bootstrap.SplitBar} this
35701 * @param {Number} newSize the new width or height
35705 * @event beforeresize
35706 * Fires before the splitter is dragged
35707 * @param {Roo.bootstrap.SplitBar} this
35709 "beforeresize" : true,
35711 "beforeapply" : true
35714 Roo.util.Observable.call(this);
35717 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
35718 onStartProxyDrag : function(x, y){
35719 this.fireEvent("beforeresize", this);
35721 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
35723 o.enableDisplayMode("block");
35724 // all splitbars share the same overlay
35725 Roo.bootstrap.SplitBar.prototype.overlay = o;
35727 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
35728 this.overlay.show();
35729 Roo.get(this.proxy).setDisplayed("block");
35730 var size = this.adapter.getElementSize(this);
35731 this.activeMinSize = this.getMinimumSize();;
35732 this.activeMaxSize = this.getMaximumSize();;
35733 var c1 = size - this.activeMinSize;
35734 var c2 = Math.max(this.activeMaxSize - size, 0);
35735 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35736 this.dd.resetConstraints();
35737 this.dd.setXConstraint(
35738 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
35739 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
35741 this.dd.setYConstraint(0, 0);
35743 this.dd.resetConstraints();
35744 this.dd.setXConstraint(0, 0);
35745 this.dd.setYConstraint(
35746 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
35747 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
35750 this.dragSpecs.startSize = size;
35751 this.dragSpecs.startPoint = [x, y];
35752 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
35756 * @private Called after the drag operation by the DDProxy
35758 onEndProxyDrag : function(e){
35759 Roo.get(this.proxy).setDisplayed(false);
35760 var endPoint = Roo.lib.Event.getXY(e);
35762 this.overlay.hide();
35765 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35766 newSize = this.dragSpecs.startSize +
35767 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
35768 endPoint[0] - this.dragSpecs.startPoint[0] :
35769 this.dragSpecs.startPoint[0] - endPoint[0]
35772 newSize = this.dragSpecs.startSize +
35773 (this.placement == Roo.bootstrap.SplitBar.TOP ?
35774 endPoint[1] - this.dragSpecs.startPoint[1] :
35775 this.dragSpecs.startPoint[1] - endPoint[1]
35778 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
35779 if(newSize != this.dragSpecs.startSize){
35780 if(this.fireEvent('beforeapply', this, newSize) !== false){
35781 this.adapter.setElementSize(this, newSize);
35782 this.fireEvent("moved", this, newSize);
35783 this.fireEvent("resize", this, newSize);
35789 * Get the adapter this SplitBar uses
35790 * @return The adapter object
35792 getAdapter : function(){
35793 return this.adapter;
35797 * Set the adapter this SplitBar uses
35798 * @param {Object} adapter A SplitBar adapter object
35800 setAdapter : function(adapter){
35801 this.adapter = adapter;
35802 this.adapter.init(this);
35806 * Gets the minimum size for the resizing element
35807 * @return {Number} The minimum size
35809 getMinimumSize : function(){
35810 return this.minSize;
35814 * Sets the minimum size for the resizing element
35815 * @param {Number} minSize The minimum size
35817 setMinimumSize : function(minSize){
35818 this.minSize = minSize;
35822 * Gets the maximum size for the resizing element
35823 * @return {Number} The maximum size
35825 getMaximumSize : function(){
35826 return this.maxSize;
35830 * Sets the maximum size for the resizing element
35831 * @param {Number} maxSize The maximum size
35833 setMaximumSize : function(maxSize){
35834 this.maxSize = maxSize;
35838 * Sets the initialize size for the resizing element
35839 * @param {Number} size The initial size
35841 setCurrentSize : function(size){
35842 var oldAnimate = this.animate;
35843 this.animate = false;
35844 this.adapter.setElementSize(this, size);
35845 this.animate = oldAnimate;
35849 * Destroy this splitbar.
35850 * @param {Boolean} removeEl True to remove the element
35852 destroy : function(removeEl){
35854 this.shim.remove();
35857 this.proxy.parentNode.removeChild(this.proxy);
35865 * @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.
35867 Roo.bootstrap.SplitBar.createProxy = function(dir){
35868 var proxy = new Roo.Element(document.createElement("div"));
35869 proxy.unselectable();
35870 var cls = 'roo-splitbar-proxy';
35871 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
35872 document.body.appendChild(proxy.dom);
35877 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
35878 * Default Adapter. It assumes the splitter and resizing element are not positioned
35879 * elements and only gets/sets the width of the element. Generally used for table based layouts.
35881 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
35884 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
35885 // do nothing for now
35886 init : function(s){
35890 * Called before drag operations to get the current size of the resizing element.
35891 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
35893 getElementSize : function(s){
35894 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35895 return s.resizingEl.getWidth();
35897 return s.resizingEl.getHeight();
35902 * Called after drag operations to set the size of the resizing element.
35903 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
35904 * @param {Number} newSize The new size to set
35905 * @param {Function} onComplete A function to be invoked when resizing is complete
35907 setElementSize : function(s, newSize, onComplete){
35908 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35910 s.resizingEl.setWidth(newSize);
35912 onComplete(s, newSize);
35915 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
35920 s.resizingEl.setHeight(newSize);
35922 onComplete(s, newSize);
35925 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
35932 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
35933 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
35934 * Adapter that moves the splitter element to align with the resized sizing element.
35935 * Used with an absolute positioned SplitBar.
35936 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
35937 * document.body, make sure you assign an id to the body element.
35939 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
35940 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
35941 this.container = Roo.get(container);
35944 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
35945 init : function(s){
35946 this.basic.init(s);
35949 getElementSize : function(s){
35950 return this.basic.getElementSize(s);
35953 setElementSize : function(s, newSize, onComplete){
35954 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
35957 moveSplitter : function(s){
35958 var yes = Roo.bootstrap.SplitBar;
35959 switch(s.placement){
35961 s.el.setX(s.resizingEl.getRight());
35964 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
35967 s.el.setY(s.resizingEl.getBottom());
35970 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
35977 * Orientation constant - Create a vertical SplitBar
35981 Roo.bootstrap.SplitBar.VERTICAL = 1;
35984 * Orientation constant - Create a horizontal SplitBar
35988 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
35991 * Placement constant - The resizing element is to the left of the splitter element
35995 Roo.bootstrap.SplitBar.LEFT = 1;
35998 * Placement constant - The resizing element is to the right of the splitter element
36002 Roo.bootstrap.SplitBar.RIGHT = 2;
36005 * Placement constant - The resizing element is positioned above the splitter element
36009 Roo.bootstrap.SplitBar.TOP = 3;
36012 * Placement constant - The resizing element is positioned under splitter element
36016 Roo.bootstrap.SplitBar.BOTTOM = 4;
36017 Roo.namespace("Roo.bootstrap.layout");/*
36019 * Ext JS Library 1.1.1
36020 * Copyright(c) 2006-2007, Ext JS, LLC.
36022 * Originally Released Under LGPL - original licence link has changed is not relivant.
36025 * <script type="text/javascript">
36029 * @class Roo.bootstrap.layout.Manager
36030 * @extends Roo.bootstrap.Component
36031 * Base class for layout managers.
36033 Roo.bootstrap.layout.Manager = function(config)
36035 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
36041 /** false to disable window resize monitoring @type Boolean */
36042 this.monitorWindowResize = true;
36047 * Fires when a layout is performed.
36048 * @param {Roo.LayoutManager} this
36052 * @event regionresized
36053 * Fires when the user resizes a region.
36054 * @param {Roo.LayoutRegion} region The resized region
36055 * @param {Number} newSize The new size (width for east/west, height for north/south)
36057 "regionresized" : true,
36059 * @event regioncollapsed
36060 * Fires when a region is collapsed.
36061 * @param {Roo.LayoutRegion} region The collapsed region
36063 "regioncollapsed" : true,
36065 * @event regionexpanded
36066 * Fires when a region is expanded.
36067 * @param {Roo.LayoutRegion} region The expanded region
36069 "regionexpanded" : true
36071 this.updating = false;
36074 this.el = Roo.get(config.el);
36080 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
36085 monitorWindowResize : true,
36091 onRender : function(ct, position)
36094 this.el = Roo.get(ct);
36097 //this.fireEvent('render',this);
36101 initEvents: function()
36105 // ie scrollbar fix
36106 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
36107 document.body.scroll = "no";
36108 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
36109 this.el.position('relative');
36111 this.id = this.el.id;
36112 this.el.addClass("roo-layout-container");
36113 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
36114 if(this.el.dom != document.body ) {
36115 this.el.on('resize', this.layout,this);
36116 this.el.on('show', this.layout,this);
36122 * Returns true if this layout is currently being updated
36123 * @return {Boolean}
36125 isUpdating : function(){
36126 return this.updating;
36130 * Suspend the LayoutManager from doing auto-layouts while
36131 * making multiple add or remove calls
36133 beginUpdate : function(){
36134 this.updating = true;
36138 * Restore auto-layouts and optionally disable the manager from performing a layout
36139 * @param {Boolean} noLayout true to disable a layout update
36141 endUpdate : function(noLayout){
36142 this.updating = false;
36148 layout: function(){
36152 onRegionResized : function(region, newSize){
36153 this.fireEvent("regionresized", region, newSize);
36157 onRegionCollapsed : function(region){
36158 this.fireEvent("regioncollapsed", region);
36161 onRegionExpanded : function(region){
36162 this.fireEvent("regionexpanded", region);
36166 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
36167 * performs box-model adjustments.
36168 * @return {Object} The size as an object {width: (the width), height: (the height)}
36170 getViewSize : function()
36173 if(this.el.dom != document.body){
36174 size = this.el.getSize();
36176 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
36178 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
36179 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36184 * Returns the Element this layout is bound to.
36185 * @return {Roo.Element}
36187 getEl : function(){
36192 * Returns the specified region.
36193 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
36194 * @return {Roo.LayoutRegion}
36196 getRegion : function(target){
36197 return this.regions[target.toLowerCase()];
36200 onWindowResize : function(){
36201 if(this.monitorWindowResize){
36208 * Ext JS Library 1.1.1
36209 * Copyright(c) 2006-2007, Ext JS, LLC.
36211 * Originally Released Under LGPL - original licence link has changed is not relivant.
36214 * <script type="text/javascript">
36217 * @class Roo.bootstrap.layout.Border
36218 * @extends Roo.bootstrap.layout.Manager
36219 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
36220 * please see: examples/bootstrap/nested.html<br><br>
36222 <b>The container the layout is rendered into can be either the body element or any other element.
36223 If it is not the body element, the container needs to either be an absolute positioned element,
36224 or you will need to add "position:relative" to the css of the container. You will also need to specify
36225 the container size if it is not the body element.</b>
36228 * Create a new Border
36229 * @param {Object} config Configuration options
36231 Roo.bootstrap.layout.Border = function(config){
36232 config = config || {};
36233 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
36237 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
36238 if(config[region]){
36239 config[region].region = region;
36240 this.addRegion(config[region]);
36246 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
36248 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
36250 parent : false, // this might point to a 'nest' or a ???
36253 * Creates and adds a new region if it doesn't already exist.
36254 * @param {String} target The target region key (north, south, east, west or center).
36255 * @param {Object} config The regions config object
36256 * @return {BorderLayoutRegion} The new region
36258 addRegion : function(config)
36260 if(!this.regions[config.region]){
36261 var r = this.factory(config);
36262 this.bindRegion(r);
36264 return this.regions[config.region];
36268 bindRegion : function(r){
36269 this.regions[r.config.region] = r;
36271 r.on("visibilitychange", this.layout, this);
36272 r.on("paneladded", this.layout, this);
36273 r.on("panelremoved", this.layout, this);
36274 r.on("invalidated", this.layout, this);
36275 r.on("resized", this.onRegionResized, this);
36276 r.on("collapsed", this.onRegionCollapsed, this);
36277 r.on("expanded", this.onRegionExpanded, this);
36281 * Performs a layout update.
36283 layout : function()
36285 if(this.updating) {
36289 // render all the rebions if they have not been done alreayd?
36290 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
36291 if(this.regions[region] && !this.regions[region].bodyEl){
36292 this.regions[region].onRender(this.el)
36296 var size = this.getViewSize();
36297 var w = size.width;
36298 var h = size.height;
36303 //var x = 0, y = 0;
36305 var rs = this.regions;
36306 var north = rs["north"];
36307 var south = rs["south"];
36308 var west = rs["west"];
36309 var east = rs["east"];
36310 var center = rs["center"];
36311 //if(this.hideOnLayout){ // not supported anymore
36312 //c.el.setStyle("display", "none");
36314 if(north && north.isVisible()){
36315 var b = north.getBox();
36316 var m = north.getMargins();
36317 b.width = w - (m.left+m.right);
36320 centerY = b.height + b.y + m.bottom;
36321 centerH -= centerY;
36322 north.updateBox(this.safeBox(b));
36324 if(south && south.isVisible()){
36325 var b = south.getBox();
36326 var m = south.getMargins();
36327 b.width = w - (m.left+m.right);
36329 var totalHeight = (b.height + m.top + m.bottom);
36330 b.y = h - totalHeight + m.top;
36331 centerH -= totalHeight;
36332 south.updateBox(this.safeBox(b));
36334 if(west && west.isVisible()){
36335 var b = west.getBox();
36336 var m = west.getMargins();
36337 b.height = centerH - (m.top+m.bottom);
36339 b.y = centerY + m.top;
36340 var totalWidth = (b.width + m.left + m.right);
36341 centerX += totalWidth;
36342 centerW -= totalWidth;
36343 west.updateBox(this.safeBox(b));
36345 if(east && east.isVisible()){
36346 var b = east.getBox();
36347 var m = east.getMargins();
36348 b.height = centerH - (m.top+m.bottom);
36349 var totalWidth = (b.width + m.left + m.right);
36350 b.x = w - totalWidth + m.left;
36351 b.y = centerY + m.top;
36352 centerW -= totalWidth;
36353 east.updateBox(this.safeBox(b));
36356 var m = center.getMargins();
36358 x: centerX + m.left,
36359 y: centerY + m.top,
36360 width: centerW - (m.left+m.right),
36361 height: centerH - (m.top+m.bottom)
36363 //if(this.hideOnLayout){
36364 //center.el.setStyle("display", "block");
36366 center.updateBox(this.safeBox(centerBox));
36369 this.fireEvent("layout", this);
36373 safeBox : function(box){
36374 box.width = Math.max(0, box.width);
36375 box.height = Math.max(0, box.height);
36380 * Adds a ContentPanel (or subclass) to this layout.
36381 * @param {String} target The target region key (north, south, east, west or center).
36382 * @param {Roo.ContentPanel} panel The panel to add
36383 * @return {Roo.ContentPanel} The added panel
36385 add : function(target, panel){
36387 target = target.toLowerCase();
36388 return this.regions[target].add(panel);
36392 * Remove a ContentPanel (or subclass) to this layout.
36393 * @param {String} target The target region key (north, south, east, west or center).
36394 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
36395 * @return {Roo.ContentPanel} The removed panel
36397 remove : function(target, panel){
36398 target = target.toLowerCase();
36399 return this.regions[target].remove(panel);
36403 * Searches all regions for a panel with the specified id
36404 * @param {String} panelId
36405 * @return {Roo.ContentPanel} The panel or null if it wasn't found
36407 findPanel : function(panelId){
36408 var rs = this.regions;
36409 for(var target in rs){
36410 if(typeof rs[target] != "function"){
36411 var p = rs[target].getPanel(panelId);
36421 * Searches all regions for a panel with the specified id and activates (shows) it.
36422 * @param {String/ContentPanel} panelId The panels id or the panel itself
36423 * @return {Roo.ContentPanel} The shown panel or null
36425 showPanel : function(panelId) {
36426 var rs = this.regions;
36427 for(var target in rs){
36428 var r = rs[target];
36429 if(typeof r != "function"){
36430 if(r.hasPanel(panelId)){
36431 return r.showPanel(panelId);
36439 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
36440 * @param {Roo.state.Provider} provider (optional) An alternate state provider
36443 restoreState : function(provider){
36445 provider = Roo.state.Manager;
36447 var sm = new Roo.LayoutStateManager();
36448 sm.init(this, provider);
36454 * Adds a xtype elements to the layout.
36458 xtype : 'ContentPanel',
36465 xtype : 'NestedLayoutPanel',
36471 items : [ ... list of content panels or nested layout panels.. ]
36475 * @param {Object} cfg Xtype definition of item to add.
36477 addxtype : function(cfg)
36479 // basically accepts a pannel...
36480 // can accept a layout region..!?!?
36481 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
36484 // theory? children can only be panels??
36486 //if (!cfg.xtype.match(/Panel$/)) {
36491 if (typeof(cfg.region) == 'undefined') {
36492 Roo.log("Failed to add Panel, region was not set");
36496 var region = cfg.region;
36502 xitems = cfg.items;
36507 if ( region == 'center') {
36508 Roo.log("Center: " + cfg.title);
36514 case 'Content': // ContentPanel (el, cfg)
36515 case 'Scroll': // ContentPanel (el, cfg)
36517 cfg.autoCreate = cfg.autoCreate || true;
36518 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36520 // var el = this.el.createChild();
36521 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
36524 this.add(region, ret);
36528 case 'TreePanel': // our new panel!
36529 cfg.el = this.el.createChild();
36530 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
36531 this.add(region, ret);
36536 // create a new Layout (which is a Border Layout...
36538 var clayout = cfg.layout;
36539 clayout.el = this.el.createChild();
36540 clayout.items = clayout.items || [];
36544 // replace this exitems with the clayout ones..
36545 xitems = clayout.items;
36547 // force background off if it's in center...
36548 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
36549 cfg.background = false;
36551 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
36554 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36555 //console.log('adding nested layout panel ' + cfg.toSource());
36556 this.add(region, ret);
36557 nb = {}; /// find first...
36562 // needs grid and region
36564 //var el = this.getRegion(region).el.createChild();
36566 *var el = this.el.createChild();
36567 // create the grid first...
36568 cfg.grid.container = el;
36569 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
36572 if (region == 'center' && this.active ) {
36573 cfg.background = false;
36576 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36578 this.add(region, ret);
36580 if (cfg.background) {
36581 // render grid on panel activation (if panel background)
36582 ret.on('activate', function(gp) {
36583 if (!gp.grid.rendered) {
36584 // gp.grid.render(el);
36588 // cfg.grid.render(el);
36594 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
36595 // it was the old xcomponent building that caused this before.
36596 // espeically if border is the top element in the tree.
36606 if (typeof(Roo[cfg.xtype]) != 'undefined') {
36608 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
36609 this.add(region, ret);
36613 throw "Can not add '" + cfg.xtype + "' to Border";
36619 this.beginUpdate();
36623 Roo.each(xitems, function(i) {
36624 region = nb && i.region ? i.region : false;
36626 var add = ret.addxtype(i);
36629 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
36630 if (!i.background) {
36631 abn[region] = nb[region] ;
36638 // make the last non-background panel active..
36639 //if (nb) { Roo.log(abn); }
36642 for(var r in abn) {
36643 region = this.getRegion(r);
36645 // tried using nb[r], but it does not work..
36647 region.showPanel(abn[r]);
36658 factory : function(cfg)
36661 var validRegions = Roo.bootstrap.layout.Border.regions;
36663 var target = cfg.region;
36666 var r = Roo.bootstrap.layout;
36670 return new r.North(cfg);
36672 return new r.South(cfg);
36674 return new r.East(cfg);
36676 return new r.West(cfg);
36678 return new r.Center(cfg);
36680 throw 'Layout region "'+target+'" not supported.';
36687 * Ext JS Library 1.1.1
36688 * Copyright(c) 2006-2007, Ext JS, LLC.
36690 * Originally Released Under LGPL - original licence link has changed is not relivant.
36693 * <script type="text/javascript">
36697 * @class Roo.bootstrap.layout.Basic
36698 * @extends Roo.util.Observable
36699 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
36700 * and does not have a titlebar, tabs or any other features. All it does is size and position
36701 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
36702 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36703 * @cfg {string} region the region that it inhabits..
36704 * @cfg {bool} skipConfig skip config?
36708 Roo.bootstrap.layout.Basic = function(config){
36710 this.mgr = config.mgr;
36712 this.position = config.region;
36714 var skipConfig = config.skipConfig;
36718 * @scope Roo.BasicLayoutRegion
36722 * @event beforeremove
36723 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
36724 * @param {Roo.LayoutRegion} this
36725 * @param {Roo.ContentPanel} panel The panel
36726 * @param {Object} e The cancel event object
36728 "beforeremove" : true,
36730 * @event invalidated
36731 * Fires when the layout for this region is changed.
36732 * @param {Roo.LayoutRegion} this
36734 "invalidated" : true,
36736 * @event visibilitychange
36737 * Fires when this region is shown or hidden
36738 * @param {Roo.LayoutRegion} this
36739 * @param {Boolean} visibility true or false
36741 "visibilitychange" : true,
36743 * @event paneladded
36744 * Fires when a panel is added.
36745 * @param {Roo.LayoutRegion} this
36746 * @param {Roo.ContentPanel} panel The panel
36748 "paneladded" : true,
36750 * @event panelremoved
36751 * Fires when a panel is removed.
36752 * @param {Roo.LayoutRegion} this
36753 * @param {Roo.ContentPanel} panel The panel
36755 "panelremoved" : true,
36757 * @event beforecollapse
36758 * Fires when this region before collapse.
36759 * @param {Roo.LayoutRegion} this
36761 "beforecollapse" : true,
36764 * Fires when this region is collapsed.
36765 * @param {Roo.LayoutRegion} this
36767 "collapsed" : true,
36770 * Fires when this region is expanded.
36771 * @param {Roo.LayoutRegion} this
36776 * Fires when this region is slid into view.
36777 * @param {Roo.LayoutRegion} this
36779 "slideshow" : true,
36782 * Fires when this region slides out of view.
36783 * @param {Roo.LayoutRegion} this
36785 "slidehide" : true,
36787 * @event panelactivated
36788 * Fires when a panel is activated.
36789 * @param {Roo.LayoutRegion} this
36790 * @param {Roo.ContentPanel} panel The activated panel
36792 "panelactivated" : true,
36795 * Fires when the user resizes this region.
36796 * @param {Roo.LayoutRegion} this
36797 * @param {Number} newSize The new size (width for east/west, height for north/south)
36801 /** A collection of panels in this region. @type Roo.util.MixedCollection */
36802 this.panels = new Roo.util.MixedCollection();
36803 this.panels.getKey = this.getPanelId.createDelegate(this);
36805 this.activePanel = null;
36806 // ensure listeners are added...
36808 if (config.listeners || config.events) {
36809 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
36810 listeners : config.listeners || {},
36811 events : config.events || {}
36815 if(skipConfig !== true){
36816 this.applyConfig(config);
36820 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
36822 getPanelId : function(p){
36826 applyConfig : function(config){
36827 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36828 this.config = config;
36833 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
36834 * the width, for horizontal (north, south) the height.
36835 * @param {Number} newSize The new width or height
36837 resizeTo : function(newSize){
36838 var el = this.el ? this.el :
36839 (this.activePanel ? this.activePanel.getEl() : null);
36841 switch(this.position){
36844 el.setWidth(newSize);
36845 this.fireEvent("resized", this, newSize);
36849 el.setHeight(newSize);
36850 this.fireEvent("resized", this, newSize);
36856 getBox : function(){
36857 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
36860 getMargins : function(){
36861 return this.margins;
36864 updateBox : function(box){
36866 var el = this.activePanel.getEl();
36867 el.dom.style.left = box.x + "px";
36868 el.dom.style.top = box.y + "px";
36869 this.activePanel.setSize(box.width, box.height);
36873 * Returns the container element for this region.
36874 * @return {Roo.Element}
36876 getEl : function(){
36877 return this.activePanel;
36881 * Returns true if this region is currently visible.
36882 * @return {Boolean}
36884 isVisible : function(){
36885 return this.activePanel ? true : false;
36888 setActivePanel : function(panel){
36889 panel = this.getPanel(panel);
36890 if(this.activePanel && this.activePanel != panel){
36891 this.activePanel.setActiveState(false);
36892 this.activePanel.getEl().setLeftTop(-10000,-10000);
36894 this.activePanel = panel;
36895 panel.setActiveState(true);
36897 panel.setSize(this.box.width, this.box.height);
36899 this.fireEvent("panelactivated", this, panel);
36900 this.fireEvent("invalidated");
36904 * Show the specified panel.
36905 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
36906 * @return {Roo.ContentPanel} The shown panel or null
36908 showPanel : function(panel){
36909 panel = this.getPanel(panel);
36911 this.setActivePanel(panel);
36917 * Get the active panel for this region.
36918 * @return {Roo.ContentPanel} The active panel or null
36920 getActivePanel : function(){
36921 return this.activePanel;
36925 * Add the passed ContentPanel(s)
36926 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36927 * @return {Roo.ContentPanel} The panel added (if only one was added)
36929 add : function(panel){
36930 if(arguments.length > 1){
36931 for(var i = 0, len = arguments.length; i < len; i++) {
36932 this.add(arguments[i]);
36936 if(this.hasPanel(panel)){
36937 this.showPanel(panel);
36940 var el = panel.getEl();
36941 if(el.dom.parentNode != this.mgr.el.dom){
36942 this.mgr.el.dom.appendChild(el.dom);
36944 if(panel.setRegion){
36945 panel.setRegion(this);
36947 this.panels.add(panel);
36948 el.setStyle("position", "absolute");
36949 if(!panel.background){
36950 this.setActivePanel(panel);
36951 if(this.config.initialSize && this.panels.getCount()==1){
36952 this.resizeTo(this.config.initialSize);
36955 this.fireEvent("paneladded", this, panel);
36960 * Returns true if the panel is in this region.
36961 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36962 * @return {Boolean}
36964 hasPanel : function(panel){
36965 if(typeof panel == "object"){ // must be panel obj
36966 panel = panel.getId();
36968 return this.getPanel(panel) ? true : false;
36972 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36973 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36974 * @param {Boolean} preservePanel Overrides the config preservePanel option
36975 * @return {Roo.ContentPanel} The panel that was removed
36977 remove : function(panel, preservePanel){
36978 panel = this.getPanel(panel);
36983 this.fireEvent("beforeremove", this, panel, e);
36984 if(e.cancel === true){
36987 var panelId = panel.getId();
36988 this.panels.removeKey(panelId);
36993 * Returns the panel specified or null if it's not in this region.
36994 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36995 * @return {Roo.ContentPanel}
36997 getPanel : function(id){
36998 if(typeof id == "object"){ // must be panel obj
37001 return this.panels.get(id);
37005 * Returns this regions position (north/south/east/west/center).
37008 getPosition: function(){
37009 return this.position;
37013 * Ext JS Library 1.1.1
37014 * Copyright(c) 2006-2007, Ext JS, LLC.
37016 * Originally Released Under LGPL - original licence link has changed is not relivant.
37019 * <script type="text/javascript">
37023 * @class Roo.bootstrap.layout.Region
37024 * @extends Roo.bootstrap.layout.Basic
37025 * This class represents a region in a layout manager.
37027 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
37028 * @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})
37029 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
37030 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
37031 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
37032 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
37033 * @cfg {String} title The title for the region (overrides panel titles)
37034 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
37035 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
37036 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
37037 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
37038 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
37039 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
37040 * the space available, similar to FireFox 1.5 tabs (defaults to false)
37041 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
37042 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
37043 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
37045 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
37046 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
37047 * @cfg {Boolean} disableTabTips True to disable tab tooltips
37048 * @cfg {Number} width For East/West panels
37049 * @cfg {Number} height For North/South panels
37050 * @cfg {Boolean} split To show the splitter
37051 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
37053 * @cfg {string} cls Extra CSS classes to add to region
37055 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37056 * @cfg {string} region the region that it inhabits..
37059 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
37060 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
37062 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
37063 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
37064 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
37066 Roo.bootstrap.layout.Region = function(config)
37068 this.applyConfig(config);
37070 var mgr = config.mgr;
37071 var pos = config.region;
37072 config.skipConfig = true;
37073 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
37076 this.onRender(mgr.el);
37079 this.visible = true;
37080 this.collapsed = false;
37081 this.unrendered_panels = [];
37084 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
37086 position: '', // set by wrapper (eg. north/south etc..)
37087 unrendered_panels : null, // unrendered panels.
37089 tabPosition : false,
37091 mgr: false, // points to 'Border'
37094 createBody : function(){
37095 /** This region's body element
37096 * @type Roo.Element */
37097 this.bodyEl = this.el.createChild({
37099 cls: "roo-layout-panel-body tab-content" // bootstrap added...
37103 onRender: function(ctr, pos)
37105 var dh = Roo.DomHelper;
37106 /** This region's container element
37107 * @type Roo.Element */
37108 this.el = dh.append(ctr.dom, {
37110 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
37112 /** This region's title element
37113 * @type Roo.Element */
37115 this.titleEl = dh.append(this.el.dom, {
37117 unselectable: "on",
37118 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
37120 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
37121 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
37125 this.titleEl.enableDisplayMode();
37126 /** This region's title text element
37127 * @type HTMLElement */
37128 this.titleTextEl = this.titleEl.dom.firstChild;
37129 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
37131 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
37132 this.closeBtn.enableDisplayMode();
37133 this.closeBtn.on("click", this.closeClicked, this);
37134 this.closeBtn.hide();
37136 this.createBody(this.config);
37137 if(this.config.hideWhenEmpty){
37139 this.on("paneladded", this.validateVisibility, this);
37140 this.on("panelremoved", this.validateVisibility, this);
37142 if(this.autoScroll){
37143 this.bodyEl.setStyle("overflow", "auto");
37145 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
37147 //if(c.titlebar !== false){
37148 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
37149 this.titleEl.hide();
37151 this.titleEl.show();
37152 if(this.config.title){
37153 this.titleTextEl.innerHTML = this.config.title;
37157 if(this.config.collapsed){
37158 this.collapse(true);
37160 if(this.config.hidden){
37164 if (this.unrendered_panels && this.unrendered_panels.length) {
37165 for (var i =0;i< this.unrendered_panels.length; i++) {
37166 this.add(this.unrendered_panels[i]);
37168 this.unrendered_panels = null;
37174 applyConfig : function(c)
37177 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
37178 var dh = Roo.DomHelper;
37179 if(c.titlebar !== false){
37180 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
37181 this.collapseBtn.on("click", this.collapse, this);
37182 this.collapseBtn.enableDisplayMode();
37184 if(c.showPin === true || this.showPin){
37185 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
37186 this.stickBtn.enableDisplayMode();
37187 this.stickBtn.on("click", this.expand, this);
37188 this.stickBtn.hide();
37193 /** This region's collapsed element
37194 * @type Roo.Element */
37197 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
37198 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
37201 if(c.floatable !== false){
37202 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
37203 this.collapsedEl.on("click", this.collapseClick, this);
37206 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
37207 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
37208 id: "message", unselectable: "on", style:{"float":"left"}});
37209 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
37211 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
37212 this.expandBtn.on("click", this.expand, this);
37216 if(this.collapseBtn){
37217 this.collapseBtn.setVisible(c.collapsible == true);
37220 this.cmargins = c.cmargins || this.cmargins ||
37221 (this.position == "west" || this.position == "east" ?
37222 {top: 0, left: 2, right:2, bottom: 0} :
37223 {top: 2, left: 0, right:0, bottom: 2});
37225 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
37228 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
37230 this.autoScroll = c.autoScroll || false;
37235 this.duration = c.duration || .30;
37236 this.slideDuration = c.slideDuration || .45;
37241 * Returns true if this region is currently visible.
37242 * @return {Boolean}
37244 isVisible : function(){
37245 return this.visible;
37249 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
37250 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
37252 //setCollapsedTitle : function(title){
37253 // title = title || " ";
37254 // if(this.collapsedTitleTextEl){
37255 // this.collapsedTitleTextEl.innerHTML = title;
37259 getBox : function(){
37261 // if(!this.collapsed){
37262 b = this.el.getBox(false, true);
37264 // b = this.collapsedEl.getBox(false, true);
37269 getMargins : function(){
37270 return this.margins;
37271 //return this.collapsed ? this.cmargins : this.margins;
37274 highlight : function(){
37275 this.el.addClass("x-layout-panel-dragover");
37278 unhighlight : function(){
37279 this.el.removeClass("x-layout-panel-dragover");
37282 updateBox : function(box)
37284 if (!this.bodyEl) {
37285 return; // not rendered yet..
37289 if(!this.collapsed){
37290 this.el.dom.style.left = box.x + "px";
37291 this.el.dom.style.top = box.y + "px";
37292 this.updateBody(box.width, box.height);
37294 this.collapsedEl.dom.style.left = box.x + "px";
37295 this.collapsedEl.dom.style.top = box.y + "px";
37296 this.collapsedEl.setSize(box.width, box.height);
37299 this.tabs.autoSizeTabs();
37303 updateBody : function(w, h)
37306 this.el.setWidth(w);
37307 w -= this.el.getBorderWidth("rl");
37308 if(this.config.adjustments){
37309 w += this.config.adjustments[0];
37312 if(h !== null && h > 0){
37313 this.el.setHeight(h);
37314 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
37315 h -= this.el.getBorderWidth("tb");
37316 if(this.config.adjustments){
37317 h += this.config.adjustments[1];
37319 this.bodyEl.setHeight(h);
37321 h = this.tabs.syncHeight(h);
37324 if(this.panelSize){
37325 w = w !== null ? w : this.panelSize.width;
37326 h = h !== null ? h : this.panelSize.height;
37328 if(this.activePanel){
37329 var el = this.activePanel.getEl();
37330 w = w !== null ? w : el.getWidth();
37331 h = h !== null ? h : el.getHeight();
37332 this.panelSize = {width: w, height: h};
37333 this.activePanel.setSize(w, h);
37335 if(Roo.isIE && this.tabs){
37336 this.tabs.el.repaint();
37341 * Returns the container element for this region.
37342 * @return {Roo.Element}
37344 getEl : function(){
37349 * Hides this region.
37352 //if(!this.collapsed){
37353 this.el.dom.style.left = "-2000px";
37356 // this.collapsedEl.dom.style.left = "-2000px";
37357 // this.collapsedEl.hide();
37359 this.visible = false;
37360 this.fireEvent("visibilitychange", this, false);
37364 * Shows this region if it was previously hidden.
37367 //if(!this.collapsed){
37370 // this.collapsedEl.show();
37372 this.visible = true;
37373 this.fireEvent("visibilitychange", this, true);
37376 closeClicked : function(){
37377 if(this.activePanel){
37378 this.remove(this.activePanel);
37382 collapseClick : function(e){
37384 e.stopPropagation();
37387 e.stopPropagation();
37393 * Collapses this region.
37394 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
37397 collapse : function(skipAnim, skipCheck = false){
37398 if(this.collapsed) {
37402 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
37404 this.collapsed = true;
37406 this.split.el.hide();
37408 if(this.config.animate && skipAnim !== true){
37409 this.fireEvent("invalidated", this);
37410 this.animateCollapse();
37412 this.el.setLocation(-20000,-20000);
37414 this.collapsedEl.show();
37415 this.fireEvent("collapsed", this);
37416 this.fireEvent("invalidated", this);
37422 animateCollapse : function(){
37427 * Expands this region if it was previously collapsed.
37428 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
37429 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
37432 expand : function(e, skipAnim){
37434 e.stopPropagation();
37436 if(!this.collapsed || this.el.hasActiveFx()) {
37440 this.afterSlideIn();
37443 this.collapsed = false;
37444 if(this.config.animate && skipAnim !== true){
37445 this.animateExpand();
37449 this.split.el.show();
37451 this.collapsedEl.setLocation(-2000,-2000);
37452 this.collapsedEl.hide();
37453 this.fireEvent("invalidated", this);
37454 this.fireEvent("expanded", this);
37458 animateExpand : function(){
37462 initTabs : function()
37464 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
37466 var ts = new Roo.bootstrap.panel.Tabs({
37467 el: this.bodyEl.dom,
37469 tabPosition: this.tabPosition ? this.tabPosition : 'top',
37470 disableTooltips: this.config.disableTabTips,
37471 toolbar : this.config.toolbar
37474 if(this.config.hideTabs){
37475 ts.stripWrap.setDisplayed(false);
37478 ts.resizeTabs = this.config.resizeTabs === true;
37479 ts.minTabWidth = this.config.minTabWidth || 40;
37480 ts.maxTabWidth = this.config.maxTabWidth || 250;
37481 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
37482 ts.monitorResize = false;
37483 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
37484 ts.bodyEl.addClass('roo-layout-tabs-body');
37485 this.panels.each(this.initPanelAsTab, this);
37488 initPanelAsTab : function(panel){
37489 var ti = this.tabs.addTab(
37493 this.config.closeOnTab && panel.isClosable(),
37496 if(panel.tabTip !== undefined){
37497 ti.setTooltip(panel.tabTip);
37499 ti.on("activate", function(){
37500 this.setActivePanel(panel);
37503 if(this.config.closeOnTab){
37504 ti.on("beforeclose", function(t, e){
37506 this.remove(panel);
37510 panel.tabItem = ti;
37515 updatePanelTitle : function(panel, title)
37517 if(this.activePanel == panel){
37518 this.updateTitle(title);
37521 var ti = this.tabs.getTab(panel.getEl().id);
37523 if(panel.tabTip !== undefined){
37524 ti.setTooltip(panel.tabTip);
37529 updateTitle : function(title){
37530 if(this.titleTextEl && !this.config.title){
37531 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
37535 setActivePanel : function(panel)
37537 panel = this.getPanel(panel);
37538 if(this.activePanel && this.activePanel != panel){
37539 if(this.activePanel.setActiveState(false) === false){
37543 this.activePanel = panel;
37544 panel.setActiveState(true);
37545 if(this.panelSize){
37546 panel.setSize(this.panelSize.width, this.panelSize.height);
37549 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
37551 this.updateTitle(panel.getTitle());
37553 this.fireEvent("invalidated", this);
37555 this.fireEvent("panelactivated", this, panel);
37559 * Shows the specified panel.
37560 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
37561 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
37563 showPanel : function(panel)
37565 panel = this.getPanel(panel);
37568 var tab = this.tabs.getTab(panel.getEl().id);
37569 if(tab.isHidden()){
37570 this.tabs.unhideTab(tab.id);
37574 this.setActivePanel(panel);
37581 * Get the active panel for this region.
37582 * @return {Roo.ContentPanel} The active panel or null
37584 getActivePanel : function(){
37585 return this.activePanel;
37588 validateVisibility : function(){
37589 if(this.panels.getCount() < 1){
37590 this.updateTitle(" ");
37591 this.closeBtn.hide();
37594 if(!this.isVisible()){
37601 * Adds the passed ContentPanel(s) to this region.
37602 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
37603 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
37605 add : function(panel)
37607 if(arguments.length > 1){
37608 for(var i = 0, len = arguments.length; i < len; i++) {
37609 this.add(arguments[i]);
37614 // if we have not been rendered yet, then we can not really do much of this..
37615 if (!this.bodyEl) {
37616 this.unrendered_panels.push(panel);
37623 if(this.hasPanel(panel)){
37624 this.showPanel(panel);
37627 panel.setRegion(this);
37628 this.panels.add(panel);
37629 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
37630 // sinle panel - no tab...?? would it not be better to render it with the tabs,
37631 // and hide them... ???
37632 this.bodyEl.dom.appendChild(panel.getEl().dom);
37633 if(panel.background !== true){
37634 this.setActivePanel(panel);
37636 this.fireEvent("paneladded", this, panel);
37643 this.initPanelAsTab(panel);
37647 if(panel.background !== true){
37648 this.tabs.activate(panel.getEl().id);
37650 this.fireEvent("paneladded", this, panel);
37655 * Hides the tab for the specified panel.
37656 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37658 hidePanel : function(panel){
37659 if(this.tabs && (panel = this.getPanel(panel))){
37660 this.tabs.hideTab(panel.getEl().id);
37665 * Unhides the tab for a previously hidden panel.
37666 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37668 unhidePanel : function(panel){
37669 if(this.tabs && (panel = this.getPanel(panel))){
37670 this.tabs.unhideTab(panel.getEl().id);
37674 clearPanels : function(){
37675 while(this.panels.getCount() > 0){
37676 this.remove(this.panels.first());
37681 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
37682 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37683 * @param {Boolean} preservePanel Overrides the config preservePanel option
37684 * @return {Roo.ContentPanel} The panel that was removed
37686 remove : function(panel, preservePanel)
37688 panel = this.getPanel(panel);
37693 this.fireEvent("beforeremove", this, panel, e);
37694 if(e.cancel === true){
37697 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
37698 var panelId = panel.getId();
37699 this.panels.removeKey(panelId);
37701 document.body.appendChild(panel.getEl().dom);
37704 this.tabs.removeTab(panel.getEl().id);
37705 }else if (!preservePanel){
37706 this.bodyEl.dom.removeChild(panel.getEl().dom);
37708 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
37709 var p = this.panels.first();
37710 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
37711 tempEl.appendChild(p.getEl().dom);
37712 this.bodyEl.update("");
37713 this.bodyEl.dom.appendChild(p.getEl().dom);
37715 this.updateTitle(p.getTitle());
37717 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
37718 this.setActivePanel(p);
37720 panel.setRegion(null);
37721 if(this.activePanel == panel){
37722 this.activePanel = null;
37724 if(this.config.autoDestroy !== false && preservePanel !== true){
37725 try{panel.destroy();}catch(e){}
37727 this.fireEvent("panelremoved", this, panel);
37732 * Returns the TabPanel component used by this region
37733 * @return {Roo.TabPanel}
37735 getTabs : function(){
37739 createTool : function(parentEl, className){
37740 var btn = Roo.DomHelper.append(parentEl, {
37742 cls: "x-layout-tools-button",
37745 cls: "roo-layout-tools-button-inner " + className,
37749 btn.addClassOnOver("roo-layout-tools-button-over");
37754 * Ext JS Library 1.1.1
37755 * Copyright(c) 2006-2007, Ext JS, LLC.
37757 * Originally Released Under LGPL - original licence link has changed is not relivant.
37760 * <script type="text/javascript">
37766 * @class Roo.SplitLayoutRegion
37767 * @extends Roo.LayoutRegion
37768 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
37770 Roo.bootstrap.layout.Split = function(config){
37771 this.cursor = config.cursor;
37772 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
37775 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
37777 splitTip : "Drag to resize.",
37778 collapsibleSplitTip : "Drag to resize. Double click to hide.",
37779 useSplitTips : false,
37781 applyConfig : function(config){
37782 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
37785 onRender : function(ctr,pos) {
37787 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
37788 if(!this.config.split){
37793 var splitEl = Roo.DomHelper.append(ctr.dom, {
37795 id: this.el.id + "-split",
37796 cls: "roo-layout-split roo-layout-split-"+this.position,
37799 /** The SplitBar for this region
37800 * @type Roo.SplitBar */
37801 // does not exist yet...
37802 Roo.log([this.position, this.orientation]);
37804 this.split = new Roo.bootstrap.SplitBar({
37805 dragElement : splitEl,
37806 resizingElement: this.el,
37807 orientation : this.orientation
37810 this.split.on("moved", this.onSplitMove, this);
37811 this.split.useShim = this.config.useShim === true;
37812 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
37813 if(this.useSplitTips){
37814 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
37816 //if(config.collapsible){
37817 // this.split.el.on("dblclick", this.collapse, this);
37820 if(typeof this.config.minSize != "undefined"){
37821 this.split.minSize = this.config.minSize;
37823 if(typeof this.config.maxSize != "undefined"){
37824 this.split.maxSize = this.config.maxSize;
37826 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
37827 this.hideSplitter();
37832 getHMaxSize : function(){
37833 var cmax = this.config.maxSize || 10000;
37834 var center = this.mgr.getRegion("center");
37835 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
37838 getVMaxSize : function(){
37839 var cmax = this.config.maxSize || 10000;
37840 var center = this.mgr.getRegion("center");
37841 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
37844 onSplitMove : function(split, newSize){
37845 this.fireEvent("resized", this, newSize);
37849 * Returns the {@link Roo.SplitBar} for this region.
37850 * @return {Roo.SplitBar}
37852 getSplitBar : function(){
37857 this.hideSplitter();
37858 Roo.bootstrap.layout.Split.superclass.hide.call(this);
37861 hideSplitter : function(){
37863 this.split.el.setLocation(-2000,-2000);
37864 this.split.el.hide();
37870 this.split.el.show();
37872 Roo.bootstrap.layout.Split.superclass.show.call(this);
37875 beforeSlide: function(){
37876 if(Roo.isGecko){// firefox overflow auto bug workaround
37877 this.bodyEl.clip();
37879 this.tabs.bodyEl.clip();
37881 if(this.activePanel){
37882 this.activePanel.getEl().clip();
37884 if(this.activePanel.beforeSlide){
37885 this.activePanel.beforeSlide();
37891 afterSlide : function(){
37892 if(Roo.isGecko){// firefox overflow auto bug workaround
37893 this.bodyEl.unclip();
37895 this.tabs.bodyEl.unclip();
37897 if(this.activePanel){
37898 this.activePanel.getEl().unclip();
37899 if(this.activePanel.afterSlide){
37900 this.activePanel.afterSlide();
37906 initAutoHide : function(){
37907 if(this.autoHide !== false){
37908 if(!this.autoHideHd){
37909 var st = new Roo.util.DelayedTask(this.slideIn, this);
37910 this.autoHideHd = {
37911 "mouseout": function(e){
37912 if(!e.within(this.el, true)){
37916 "mouseover" : function(e){
37922 this.el.on(this.autoHideHd);
37926 clearAutoHide : function(){
37927 if(this.autoHide !== false){
37928 this.el.un("mouseout", this.autoHideHd.mouseout);
37929 this.el.un("mouseover", this.autoHideHd.mouseover);
37933 clearMonitor : function(){
37934 Roo.get(document).un("click", this.slideInIf, this);
37937 // these names are backwards but not changed for compat
37938 slideOut : function(){
37939 if(this.isSlid || this.el.hasActiveFx()){
37942 this.isSlid = true;
37943 if(this.collapseBtn){
37944 this.collapseBtn.hide();
37946 this.closeBtnState = this.closeBtn.getStyle('display');
37947 this.closeBtn.hide();
37949 this.stickBtn.show();
37952 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
37953 this.beforeSlide();
37954 this.el.setStyle("z-index", 10001);
37955 this.el.slideIn(this.getSlideAnchor(), {
37956 callback: function(){
37958 this.initAutoHide();
37959 Roo.get(document).on("click", this.slideInIf, this);
37960 this.fireEvent("slideshow", this);
37967 afterSlideIn : function(){
37968 this.clearAutoHide();
37969 this.isSlid = false;
37970 this.clearMonitor();
37971 this.el.setStyle("z-index", "");
37972 if(this.collapseBtn){
37973 this.collapseBtn.show();
37975 this.closeBtn.setStyle('display', this.closeBtnState);
37977 this.stickBtn.hide();
37979 this.fireEvent("slidehide", this);
37982 slideIn : function(cb){
37983 if(!this.isSlid || this.el.hasActiveFx()){
37987 this.isSlid = false;
37988 this.beforeSlide();
37989 this.el.slideOut(this.getSlideAnchor(), {
37990 callback: function(){
37991 this.el.setLeftTop(-10000, -10000);
37993 this.afterSlideIn();
38001 slideInIf : function(e){
38002 if(!e.within(this.el)){
38007 animateCollapse : function(){
38008 this.beforeSlide();
38009 this.el.setStyle("z-index", 20000);
38010 var anchor = this.getSlideAnchor();
38011 this.el.slideOut(anchor, {
38012 callback : function(){
38013 this.el.setStyle("z-index", "");
38014 this.collapsedEl.slideIn(anchor, {duration:.3});
38016 this.el.setLocation(-10000,-10000);
38018 this.fireEvent("collapsed", this);
38025 animateExpand : function(){
38026 this.beforeSlide();
38027 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
38028 this.el.setStyle("z-index", 20000);
38029 this.collapsedEl.hide({
38032 this.el.slideIn(this.getSlideAnchor(), {
38033 callback : function(){
38034 this.el.setStyle("z-index", "");
38037 this.split.el.show();
38039 this.fireEvent("invalidated", this);
38040 this.fireEvent("expanded", this);
38068 getAnchor : function(){
38069 return this.anchors[this.position];
38072 getCollapseAnchor : function(){
38073 return this.canchors[this.position];
38076 getSlideAnchor : function(){
38077 return this.sanchors[this.position];
38080 getAlignAdj : function(){
38081 var cm = this.cmargins;
38082 switch(this.position){
38098 getExpandAdj : function(){
38099 var c = this.collapsedEl, cm = this.cmargins;
38100 switch(this.position){
38102 return [-(cm.right+c.getWidth()+cm.left), 0];
38105 return [cm.right+c.getWidth()+cm.left, 0];
38108 return [0, -(cm.top+cm.bottom+c.getHeight())];
38111 return [0, cm.top+cm.bottom+c.getHeight()];
38117 * Ext JS Library 1.1.1
38118 * Copyright(c) 2006-2007, Ext JS, LLC.
38120 * Originally Released Under LGPL - original licence link has changed is not relivant.
38123 * <script type="text/javascript">
38126 * These classes are private internal classes
38128 Roo.bootstrap.layout.Center = function(config){
38129 config.region = "center";
38130 Roo.bootstrap.layout.Region.call(this, config);
38131 this.visible = true;
38132 this.minWidth = config.minWidth || 20;
38133 this.minHeight = config.minHeight || 20;
38136 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
38138 // center panel can't be hidden
38142 // center panel can't be hidden
38145 getMinWidth: function(){
38146 return this.minWidth;
38149 getMinHeight: function(){
38150 return this.minHeight;
38164 Roo.bootstrap.layout.North = function(config)
38166 config.region = 'north';
38167 config.cursor = 'n-resize';
38169 Roo.bootstrap.layout.Split.call(this, config);
38173 this.split.placement = Roo.bootstrap.SplitBar.TOP;
38174 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38175 this.split.el.addClass("roo-layout-split-v");
38177 var size = config.initialSize || config.height;
38178 if(typeof size != "undefined"){
38179 this.el.setHeight(size);
38182 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
38184 orientation: Roo.bootstrap.SplitBar.VERTICAL,
38188 getBox : function(){
38189 if(this.collapsed){
38190 return this.collapsedEl.getBox();
38192 var box = this.el.getBox();
38194 box.height += this.split.el.getHeight();
38199 updateBox : function(box){
38200 if(this.split && !this.collapsed){
38201 box.height -= this.split.el.getHeight();
38202 this.split.el.setLeft(box.x);
38203 this.split.el.setTop(box.y+box.height);
38204 this.split.el.setWidth(box.width);
38206 if(this.collapsed){
38207 this.updateBody(box.width, null);
38209 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38217 Roo.bootstrap.layout.South = function(config){
38218 config.region = 'south';
38219 config.cursor = 's-resize';
38220 Roo.bootstrap.layout.Split.call(this, config);
38222 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
38223 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38224 this.split.el.addClass("roo-layout-split-v");
38226 var size = config.initialSize || config.height;
38227 if(typeof size != "undefined"){
38228 this.el.setHeight(size);
38232 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
38233 orientation: Roo.bootstrap.SplitBar.VERTICAL,
38234 getBox : function(){
38235 if(this.collapsed){
38236 return this.collapsedEl.getBox();
38238 var box = this.el.getBox();
38240 var sh = this.split.el.getHeight();
38247 updateBox : function(box){
38248 if(this.split && !this.collapsed){
38249 var sh = this.split.el.getHeight();
38252 this.split.el.setLeft(box.x);
38253 this.split.el.setTop(box.y-sh);
38254 this.split.el.setWidth(box.width);
38256 if(this.collapsed){
38257 this.updateBody(box.width, null);
38259 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38263 Roo.bootstrap.layout.East = function(config){
38264 config.region = "east";
38265 config.cursor = "e-resize";
38266 Roo.bootstrap.layout.Split.call(this, config);
38268 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
38269 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
38270 this.split.el.addClass("roo-layout-split-h");
38272 var size = config.initialSize || config.width;
38273 if(typeof size != "undefined"){
38274 this.el.setWidth(size);
38277 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
38278 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
38279 getBox : function(){
38280 if(this.collapsed){
38281 return this.collapsedEl.getBox();
38283 var box = this.el.getBox();
38285 var sw = this.split.el.getWidth();
38292 updateBox : function(box){
38293 if(this.split && !this.collapsed){
38294 var sw = this.split.el.getWidth();
38296 this.split.el.setLeft(box.x);
38297 this.split.el.setTop(box.y);
38298 this.split.el.setHeight(box.height);
38301 if(this.collapsed){
38302 this.updateBody(null, box.height);
38304 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38308 Roo.bootstrap.layout.West = function(config){
38309 config.region = "west";
38310 config.cursor = "w-resize";
38312 Roo.bootstrap.layout.Split.call(this, config);
38314 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
38315 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
38316 this.split.el.addClass("roo-layout-split-h");
38320 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
38321 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
38323 onRender: function(ctr, pos)
38325 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
38326 var size = this.config.initialSize || this.config.width;
38327 if(typeof size != "undefined"){
38328 this.el.setWidth(size);
38332 getBox : function(){
38333 if(this.collapsed){
38334 return this.collapsedEl.getBox();
38336 var box = this.el.getBox();
38338 box.width += this.split.el.getWidth();
38343 updateBox : function(box){
38344 if(this.split && !this.collapsed){
38345 var sw = this.split.el.getWidth();
38347 this.split.el.setLeft(box.x+box.width);
38348 this.split.el.setTop(box.y);
38349 this.split.el.setHeight(box.height);
38351 if(this.collapsed){
38352 this.updateBody(null, box.height);
38354 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38356 });Roo.namespace("Roo.bootstrap.panel");/*
38358 * Ext JS Library 1.1.1
38359 * Copyright(c) 2006-2007, Ext JS, LLC.
38361 * Originally Released Under LGPL - original licence link has changed is not relivant.
38364 * <script type="text/javascript">
38367 * @class Roo.ContentPanel
38368 * @extends Roo.util.Observable
38369 * A basic ContentPanel element.
38370 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
38371 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
38372 * @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
38373 * @cfg {Boolean} closable True if the panel can be closed/removed
38374 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
38375 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
38376 * @cfg {Toolbar} toolbar A toolbar for this panel
38377 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
38378 * @cfg {String} title The title for this panel
38379 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
38380 * @cfg {String} url Calls {@link #setUrl} with this value
38381 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
38382 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
38383 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
38384 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
38385 * @cfg {Boolean} badges render the badges
38388 * Create a new ContentPanel.
38389 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
38390 * @param {String/Object} config A string to set only the title or a config object
38391 * @param {String} content (optional) Set the HTML content for this panel
38392 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
38394 Roo.bootstrap.panel.Content = function( config){
38396 this.tpl = config.tpl || false;
38398 var el = config.el;
38399 var content = config.content;
38401 if(config.autoCreate){ // xtype is available if this is called from factory
38404 this.el = Roo.get(el);
38405 if(!this.el && config && config.autoCreate){
38406 if(typeof config.autoCreate == "object"){
38407 if(!config.autoCreate.id){
38408 config.autoCreate.id = config.id||el;
38410 this.el = Roo.DomHelper.append(document.body,
38411 config.autoCreate, true);
38413 var elcfg = { tag: "div",
38414 cls: "roo-layout-inactive-content",
38418 elcfg.html = config.html;
38422 this.el = Roo.DomHelper.append(document.body, elcfg , true);
38425 this.closable = false;
38426 this.loaded = false;
38427 this.active = false;
38430 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
38432 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
38434 this.wrapEl = this.el; //this.el.wrap();
38436 if (config.toolbar.items) {
38437 ti = config.toolbar.items ;
38438 delete config.toolbar.items ;
38442 this.toolbar.render(this.wrapEl, 'before');
38443 for(var i =0;i < ti.length;i++) {
38444 // Roo.log(['add child', items[i]]);
38445 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
38447 this.toolbar.items = nitems;
38448 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
38449 delete config.toolbar;
38453 // xtype created footer. - not sure if will work as we normally have to render first..
38454 if (this.footer && !this.footer.el && this.footer.xtype) {
38455 if (!this.wrapEl) {
38456 this.wrapEl = this.el.wrap();
38459 this.footer.container = this.wrapEl.createChild();
38461 this.footer = Roo.factory(this.footer, Roo);
38466 if(typeof config == "string"){
38467 this.title = config;
38469 Roo.apply(this, config);
38473 this.resizeEl = Roo.get(this.resizeEl, true);
38475 this.resizeEl = this.el;
38477 // handle view.xtype
38485 * Fires when this panel is activated.
38486 * @param {Roo.ContentPanel} this
38490 * @event deactivate
38491 * Fires when this panel is activated.
38492 * @param {Roo.ContentPanel} this
38494 "deactivate" : true,
38498 * Fires when this panel is resized if fitToFrame is true.
38499 * @param {Roo.ContentPanel} this
38500 * @param {Number} width The width after any component adjustments
38501 * @param {Number} height The height after any component adjustments
38507 * Fires when this tab is created
38508 * @param {Roo.ContentPanel} this
38519 if(this.autoScroll){
38520 this.resizeEl.setStyle("overflow", "auto");
38522 // fix randome scrolling
38523 //this.el.on('scroll', function() {
38524 // Roo.log('fix random scolling');
38525 // this.scrollTo('top',0);
38528 content = content || this.content;
38530 this.setContent(content);
38532 if(config && config.url){
38533 this.setUrl(this.url, this.params, this.loadOnce);
38538 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
38540 if (this.view && typeof(this.view.xtype) != 'undefined') {
38541 this.view.el = this.el.appendChild(document.createElement("div"));
38542 this.view = Roo.factory(this.view);
38543 this.view.render && this.view.render(false, '');
38547 this.fireEvent('render', this);
38550 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
38554 setRegion : function(region){
38555 this.region = region;
38556 this.setActiveClass(region && !this.background);
38560 setActiveClass: function(state)
38563 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
38564 this.el.setStyle('position','relative');
38566 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
38567 this.el.setStyle('position', 'absolute');
38572 * Returns the toolbar for this Panel if one was configured.
38573 * @return {Roo.Toolbar}
38575 getToolbar : function(){
38576 return this.toolbar;
38579 setActiveState : function(active)
38581 this.active = active;
38582 this.setActiveClass(active);
38584 if(this.fireEvent("deactivate", this) === false){
38589 this.fireEvent("activate", this);
38593 * Updates this panel's element
38594 * @param {String} content The new content
38595 * @param {Boolean} loadScripts (optional) true to look for and process scripts
38597 setContent : function(content, loadScripts){
38598 this.el.update(content, loadScripts);
38601 ignoreResize : function(w, h){
38602 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
38605 this.lastSize = {width: w, height: h};
38610 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
38611 * @return {Roo.UpdateManager} The UpdateManager
38613 getUpdateManager : function(){
38614 return this.el.getUpdateManager();
38617 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
38618 * @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:
38621 url: "your-url.php",
38622 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
38623 callback: yourFunction,
38624 scope: yourObject, //(optional scope)
38627 text: "Loading...",
38632 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
38633 * 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.
38634 * @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}
38635 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
38636 * @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.
38637 * @return {Roo.ContentPanel} this
38640 var um = this.el.getUpdateManager();
38641 um.update.apply(um, arguments);
38647 * 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.
38648 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
38649 * @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)
38650 * @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)
38651 * @return {Roo.UpdateManager} The UpdateManager
38653 setUrl : function(url, params, loadOnce){
38654 if(this.refreshDelegate){
38655 this.removeListener("activate", this.refreshDelegate);
38657 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38658 this.on("activate", this.refreshDelegate);
38659 return this.el.getUpdateManager();
38662 _handleRefresh : function(url, params, loadOnce){
38663 if(!loadOnce || !this.loaded){
38664 var updater = this.el.getUpdateManager();
38665 updater.update(url, params, this._setLoaded.createDelegate(this));
38669 _setLoaded : function(){
38670 this.loaded = true;
38674 * Returns this panel's id
38677 getId : function(){
38682 * Returns this panel's element - used by regiosn to add.
38683 * @return {Roo.Element}
38685 getEl : function(){
38686 return this.wrapEl || this.el;
38691 adjustForComponents : function(width, height)
38693 //Roo.log('adjustForComponents ');
38694 if(this.resizeEl != this.el){
38695 width -= this.el.getFrameWidth('lr');
38696 height -= this.el.getFrameWidth('tb');
38699 var te = this.toolbar.getEl();
38700 te.setWidth(width);
38701 height -= te.getHeight();
38704 var te = this.footer.getEl();
38705 te.setWidth(width);
38706 height -= te.getHeight();
38710 if(this.adjustments){
38711 width += this.adjustments[0];
38712 height += this.adjustments[1];
38714 return {"width": width, "height": height};
38717 setSize : function(width, height){
38718 if(this.fitToFrame && !this.ignoreResize(width, height)){
38719 if(this.fitContainer && this.resizeEl != this.el){
38720 this.el.setSize(width, height);
38722 var size = this.adjustForComponents(width, height);
38723 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
38724 this.fireEvent('resize', this, size.width, size.height);
38729 * Returns this panel's title
38732 getTitle : function(){
38734 if (typeof(this.title) != 'object') {
38739 for (var k in this.title) {
38740 if (!this.title.hasOwnProperty(k)) {
38744 if (k.indexOf('-') >= 0) {
38745 var s = k.split('-');
38746 for (var i = 0; i<s.length; i++) {
38747 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
38750 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
38757 * Set this panel's title
38758 * @param {String} title
38760 setTitle : function(title){
38761 this.title = title;
38763 this.region.updatePanelTitle(this, title);
38768 * Returns true is this panel was configured to be closable
38769 * @return {Boolean}
38771 isClosable : function(){
38772 return this.closable;
38775 beforeSlide : function(){
38777 this.resizeEl.clip();
38780 afterSlide : function(){
38782 this.resizeEl.unclip();
38786 * Force a content refresh from the URL specified in the {@link #setUrl} method.
38787 * Will fail silently if the {@link #setUrl} method has not been called.
38788 * This does not activate the panel, just updates its content.
38790 refresh : function(){
38791 if(this.refreshDelegate){
38792 this.loaded = false;
38793 this.refreshDelegate();
38798 * Destroys this panel
38800 destroy : function(){
38801 this.el.removeAllListeners();
38802 var tempEl = document.createElement("span");
38803 tempEl.appendChild(this.el.dom);
38804 tempEl.innerHTML = "";
38810 * form - if the content panel contains a form - this is a reference to it.
38811 * @type {Roo.form.Form}
38815 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
38816 * This contains a reference to it.
38822 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
38832 * @param {Object} cfg Xtype definition of item to add.
38836 getChildContainer: function () {
38837 return this.getEl();
38842 var ret = new Roo.factory(cfg);
38847 if (cfg.xtype.match(/^Form$/)) {
38850 //if (this.footer) {
38851 // el = this.footer.container.insertSibling(false, 'before');
38853 el = this.el.createChild();
38856 this.form = new Roo.form.Form(cfg);
38859 if ( this.form.allItems.length) {
38860 this.form.render(el.dom);
38864 // should only have one of theses..
38865 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
38866 // views.. should not be just added - used named prop 'view''
38868 cfg.el = this.el.appendChild(document.createElement("div"));
38871 var ret = new Roo.factory(cfg);
38873 ret.render && ret.render(false, ''); // render blank..
38883 * @class Roo.bootstrap.panel.Grid
38884 * @extends Roo.bootstrap.panel.Content
38886 * Create a new GridPanel.
38887 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
38888 * @param {Object} config A the config object
38894 Roo.bootstrap.panel.Grid = function(config)
38898 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
38899 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
38901 config.el = this.wrapper;
38902 //this.el = this.wrapper;
38904 if (config.container) {
38905 // ctor'ed from a Border/panel.grid
38908 this.wrapper.setStyle("overflow", "hidden");
38909 this.wrapper.addClass('roo-grid-container');
38914 if(config.toolbar){
38915 var tool_el = this.wrapper.createChild();
38916 this.toolbar = Roo.factory(config.toolbar);
38918 if (config.toolbar.items) {
38919 ti = config.toolbar.items ;
38920 delete config.toolbar.items ;
38924 this.toolbar.render(tool_el);
38925 for(var i =0;i < ti.length;i++) {
38926 // Roo.log(['add child', items[i]]);
38927 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
38929 this.toolbar.items = nitems;
38931 delete config.toolbar;
38934 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
38935 config.grid.scrollBody = true;;
38936 config.grid.monitorWindowResize = false; // turn off autosizing
38937 config.grid.autoHeight = false;
38938 config.grid.autoWidth = false;
38940 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
38942 if (config.background) {
38943 // render grid on panel activation (if panel background)
38944 this.on('activate', function(gp) {
38945 if (!gp.grid.rendered) {
38946 gp.grid.render(this.wrapper);
38947 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
38952 this.grid.render(this.wrapper);
38953 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
38956 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
38957 // ??? needed ??? config.el = this.wrapper;
38962 // xtype created footer. - not sure if will work as we normally have to render first..
38963 if (this.footer && !this.footer.el && this.footer.xtype) {
38965 var ctr = this.grid.getView().getFooterPanel(true);
38966 this.footer.dataSource = this.grid.dataSource;
38967 this.footer = Roo.factory(this.footer, Roo);
38968 this.footer.render(ctr);
38978 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
38979 getId : function(){
38980 return this.grid.id;
38984 * Returns the grid for this panel
38985 * @return {Roo.bootstrap.Table}
38987 getGrid : function(){
38991 setSize : function(width, height){
38992 if(!this.ignoreResize(width, height)){
38993 var grid = this.grid;
38994 var size = this.adjustForComponents(width, height);
38995 var gridel = grid.getGridEl();
38996 gridel.setSize(size.width, size.height);
38998 var thd = grid.getGridEl().select('thead',true).first();
38999 var tbd = grid.getGridEl().select('tbody', true).first();
39001 tbd.setSize(width, height - thd.getHeight());
39010 beforeSlide : function(){
39011 this.grid.getView().scroller.clip();
39014 afterSlide : function(){
39015 this.grid.getView().scroller.unclip();
39018 destroy : function(){
39019 this.grid.destroy();
39021 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
39026 * @class Roo.bootstrap.panel.Nest
39027 * @extends Roo.bootstrap.panel.Content
39029 * Create a new Panel, that can contain a layout.Border.
39032 * @param {Roo.BorderLayout} layout The layout for this panel
39033 * @param {String/Object} config A string to set only the title or a config object
39035 Roo.bootstrap.panel.Nest = function(config)
39037 // construct with only one argument..
39038 /* FIXME - implement nicer consturctors
39039 if (layout.layout) {
39041 layout = config.layout;
39042 delete config.layout;
39044 if (layout.xtype && !layout.getEl) {
39045 // then layout needs constructing..
39046 layout = Roo.factory(layout, Roo);
39050 config.el = config.layout.getEl();
39052 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
39054 config.layout.monitorWindowResize = false; // turn off autosizing
39055 this.layout = config.layout;
39056 this.layout.getEl().addClass("roo-layout-nested-layout");
39057 this.layout.parent = this;
39064 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
39066 setSize : function(width, height){
39067 if(!this.ignoreResize(width, height)){
39068 var size = this.adjustForComponents(width, height);
39069 var el = this.layout.getEl();
39070 if (size.height < 1) {
39071 el.setWidth(size.width);
39073 el.setSize(size.width, size.height);
39075 var touch = el.dom.offsetWidth;
39076 this.layout.layout();
39077 // ie requires a double layout on the first pass
39078 if(Roo.isIE && !this.initialized){
39079 this.initialized = true;
39080 this.layout.layout();
39085 // activate all subpanels if not currently active..
39087 setActiveState : function(active){
39088 this.active = active;
39089 this.setActiveClass(active);
39092 this.fireEvent("deactivate", this);
39096 this.fireEvent("activate", this);
39097 // not sure if this should happen before or after..
39098 if (!this.layout) {
39099 return; // should not happen..
39102 for (var r in this.layout.regions) {
39103 reg = this.layout.getRegion(r);
39104 if (reg.getActivePanel()) {
39105 //reg.showPanel(reg.getActivePanel()); // force it to activate..
39106 reg.setActivePanel(reg.getActivePanel());
39109 if (!reg.panels.length) {
39112 reg.showPanel(reg.getPanel(0));
39121 * Returns the nested BorderLayout for this panel
39122 * @return {Roo.BorderLayout}
39124 getLayout : function(){
39125 return this.layout;
39129 * Adds a xtype elements to the layout of the nested panel
39133 xtype : 'ContentPanel',
39140 xtype : 'NestedLayoutPanel',
39146 items : [ ... list of content panels or nested layout panels.. ]
39150 * @param {Object} cfg Xtype definition of item to add.
39152 addxtype : function(cfg) {
39153 return this.layout.addxtype(cfg);
39158 * Ext JS Library 1.1.1
39159 * Copyright(c) 2006-2007, Ext JS, LLC.
39161 * Originally Released Under LGPL - original licence link has changed is not relivant.
39164 * <script type="text/javascript">
39167 * @class Roo.TabPanel
39168 * @extends Roo.util.Observable
39169 * A lightweight tab container.
39173 // basic tabs 1, built from existing content
39174 var tabs = new Roo.TabPanel("tabs1");
39175 tabs.addTab("script", "View Script");
39176 tabs.addTab("markup", "View Markup");
39177 tabs.activate("script");
39179 // more advanced tabs, built from javascript
39180 var jtabs = new Roo.TabPanel("jtabs");
39181 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
39183 // set up the UpdateManager
39184 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
39185 var updater = tab2.getUpdateManager();
39186 updater.setDefaultUrl("ajax1.htm");
39187 tab2.on('activate', updater.refresh, updater, true);
39189 // Use setUrl for Ajax loading
39190 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
39191 tab3.setUrl("ajax2.htm", null, true);
39194 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
39197 jtabs.activate("jtabs-1");
39200 * Create a new TabPanel.
39201 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
39202 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
39204 Roo.bootstrap.panel.Tabs = function(config){
39206 * The container element for this TabPanel.
39207 * @type Roo.Element
39209 this.el = Roo.get(config.el);
39212 if(typeof config == "boolean"){
39213 this.tabPosition = config ? "bottom" : "top";
39215 Roo.apply(this, config);
39219 if(this.tabPosition == "bottom"){
39220 // if tabs are at the bottom = create the body first.
39221 this.bodyEl = Roo.get(this.createBody(this.el.dom));
39222 this.el.addClass("roo-tabs-bottom");
39224 // next create the tabs holders
39226 if (this.tabPosition == "west"){
39228 var reg = this.region; // fake it..
39230 if (!reg.mgr.parent) {
39233 reg = reg.mgr.parent.region;
39235 Roo.log("got nest?");
39237 if (reg.mgr.getRegion('west')) {
39238 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
39239 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
39240 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
39241 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
39242 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
39250 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
39251 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
39252 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
39253 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
39258 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
39261 // finally - if tabs are at the top, then create the body last..
39262 if(this.tabPosition != "bottom"){
39263 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
39264 * @type Roo.Element
39266 this.bodyEl = Roo.get(this.createBody(this.el.dom));
39267 this.el.addClass("roo-tabs-top");
39271 this.bodyEl.setStyle("position", "relative");
39273 this.active = null;
39274 this.activateDelegate = this.activate.createDelegate(this);
39279 * Fires when the active tab changes
39280 * @param {Roo.TabPanel} this
39281 * @param {Roo.TabPanelItem} activePanel The new active tab
39285 * @event beforetabchange
39286 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
39287 * @param {Roo.TabPanel} this
39288 * @param {Object} e Set cancel to true on this object to cancel the tab change
39289 * @param {Roo.TabPanelItem} tab The tab being changed to
39291 "beforetabchange" : true
39294 Roo.EventManager.onWindowResize(this.onResize, this);
39295 this.cpad = this.el.getPadding("lr");
39296 this.hiddenCount = 0;
39299 // toolbar on the tabbar support...
39300 if (this.toolbar) {
39301 alert("no toolbar support yet");
39302 this.toolbar = false;
39304 var tcfg = this.toolbar;
39305 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
39306 this.toolbar = new Roo.Toolbar(tcfg);
39307 if (Roo.isSafari) {
39308 var tbl = tcfg.container.child('table', true);
39309 tbl.setAttribute('width', '100%');
39317 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
39320 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
39322 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
39324 tabPosition : "top",
39326 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
39328 currentTabWidth : 0,
39330 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
39334 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
39338 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
39340 preferredTabWidth : 175,
39342 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
39344 resizeTabs : false,
39346 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
39348 monitorResize : true,
39350 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
39352 toolbar : false, // set by caller..
39354 region : false, /// set by caller
39356 disableTooltips : true, // not used yet...
39359 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
39360 * @param {String} id The id of the div to use <b>or create</b>
39361 * @param {String} text The text for the tab
39362 * @param {String} content (optional) Content to put in the TabPanelItem body
39363 * @param {Boolean} closable (optional) True to create a close icon on the tab
39364 * @return {Roo.TabPanelItem} The created TabPanelItem
39366 addTab : function(id, text, content, closable, tpl)
39368 var item = new Roo.bootstrap.panel.TabItem({
39372 closable : closable,
39375 this.addTabItem(item);
39377 item.setContent(content);
39383 * Returns the {@link Roo.TabPanelItem} with the specified id/index
39384 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
39385 * @return {Roo.TabPanelItem}
39387 getTab : function(id){
39388 return this.items[id];
39392 * Hides the {@link Roo.TabPanelItem} with the specified id/index
39393 * @param {String/Number} id The id or index of the TabPanelItem to hide.
39395 hideTab : function(id){
39396 var t = this.items[id];
39399 this.hiddenCount++;
39400 this.autoSizeTabs();
39405 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
39406 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
39408 unhideTab : function(id){
39409 var t = this.items[id];
39411 t.setHidden(false);
39412 this.hiddenCount--;
39413 this.autoSizeTabs();
39418 * Adds an existing {@link Roo.TabPanelItem}.
39419 * @param {Roo.TabPanelItem} item The TabPanelItem to add
39421 addTabItem : function(item)
39423 this.items[item.id] = item;
39424 this.items.push(item);
39425 this.autoSizeTabs();
39426 // if(this.resizeTabs){
39427 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
39428 // this.autoSizeTabs();
39430 // item.autoSize();
39435 * Removes a {@link Roo.TabPanelItem}.
39436 * @param {String/Number} id The id or index of the TabPanelItem to remove.
39438 removeTab : function(id){
39439 var items = this.items;
39440 var tab = items[id];
39441 if(!tab) { return; }
39442 var index = items.indexOf(tab);
39443 if(this.active == tab && items.length > 1){
39444 var newTab = this.getNextAvailable(index);
39449 this.stripEl.dom.removeChild(tab.pnode.dom);
39450 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
39451 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
39453 items.splice(index, 1);
39454 delete this.items[tab.id];
39455 tab.fireEvent("close", tab);
39456 tab.purgeListeners();
39457 this.autoSizeTabs();
39460 getNextAvailable : function(start){
39461 var items = this.items;
39463 // look for a next tab that will slide over to
39464 // replace the one being removed
39465 while(index < items.length){
39466 var item = items[++index];
39467 if(item && !item.isHidden()){
39471 // if one isn't found select the previous tab (on the left)
39474 var item = items[--index];
39475 if(item && !item.isHidden()){
39483 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
39484 * @param {String/Number} id The id or index of the TabPanelItem to disable.
39486 disableTab : function(id){
39487 var tab = this.items[id];
39488 if(tab && this.active != tab){
39494 * Enables a {@link Roo.TabPanelItem} that is disabled.
39495 * @param {String/Number} id The id or index of the TabPanelItem to enable.
39497 enableTab : function(id){
39498 var tab = this.items[id];
39503 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
39504 * @param {String/Number} id The id or index of the TabPanelItem to activate.
39505 * @return {Roo.TabPanelItem} The TabPanelItem.
39507 activate : function(id)
39509 //Roo.log('activite:' + id);
39511 var tab = this.items[id];
39515 if(tab == this.active || tab.disabled){
39519 this.fireEvent("beforetabchange", this, e, tab);
39520 if(e.cancel !== true && !tab.disabled){
39522 this.active.hide();
39524 this.active = this.items[id];
39525 this.active.show();
39526 this.fireEvent("tabchange", this, this.active);
39532 * Gets the active {@link Roo.TabPanelItem}.
39533 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
39535 getActiveTab : function(){
39536 return this.active;
39540 * Updates the tab body element to fit the height of the container element
39541 * for overflow scrolling
39542 * @param {Number} targetHeight (optional) Override the starting height from the elements height
39544 syncHeight : function(targetHeight){
39545 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
39546 var bm = this.bodyEl.getMargins();
39547 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
39548 this.bodyEl.setHeight(newHeight);
39552 onResize : function(){
39553 if(this.monitorResize){
39554 this.autoSizeTabs();
39559 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
39561 beginUpdate : function(){
39562 this.updating = true;
39566 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
39568 endUpdate : function(){
39569 this.updating = false;
39570 this.autoSizeTabs();
39574 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
39576 autoSizeTabs : function()
39578 var count = this.items.length;
39579 var vcount = count - this.hiddenCount;
39582 this.stripEl.hide();
39584 this.stripEl.show();
39587 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
39592 var w = Math.max(this.el.getWidth() - this.cpad, 10);
39593 var availWidth = Math.floor(w / vcount);
39594 var b = this.stripBody;
39595 if(b.getWidth() > w){
39596 var tabs = this.items;
39597 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
39598 if(availWidth < this.minTabWidth){
39599 /*if(!this.sleft){ // incomplete scrolling code
39600 this.createScrollButtons();
39603 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
39606 if(this.currentTabWidth < this.preferredTabWidth){
39607 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
39613 * Returns the number of tabs in this TabPanel.
39616 getCount : function(){
39617 return this.items.length;
39621 * Resizes all the tabs to the passed width
39622 * @param {Number} The new width
39624 setTabWidth : function(width){
39625 this.currentTabWidth = width;
39626 for(var i = 0, len = this.items.length; i < len; i++) {
39627 if(!this.items[i].isHidden()) {
39628 this.items[i].setWidth(width);
39634 * Destroys this TabPanel
39635 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
39637 destroy : function(removeEl){
39638 Roo.EventManager.removeResizeListener(this.onResize, this);
39639 for(var i = 0, len = this.items.length; i < len; i++){
39640 this.items[i].purgeListeners();
39642 if(removeEl === true){
39643 this.el.update("");
39648 createStrip : function(container)
39650 var strip = document.createElement("nav");
39651 strip.className = Roo.bootstrap.version == 4 ?
39652 "navbar-light bg-light" :
39653 "navbar navbar-default"; //"x-tabs-wrap";
39654 container.appendChild(strip);
39658 createStripList : function(strip)
39660 // div wrapper for retard IE
39661 // returns the "tr" element.
39662 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
39663 //'<div class="x-tabs-strip-wrap">'+
39664 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
39665 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
39666 return strip.firstChild; //.firstChild.firstChild.firstChild;
39668 createBody : function(container)
39670 var body = document.createElement("div");
39671 Roo.id(body, "tab-body");
39672 //Roo.fly(body).addClass("x-tabs-body");
39673 Roo.fly(body).addClass("tab-content");
39674 container.appendChild(body);
39677 createItemBody :function(bodyEl, id){
39678 var body = Roo.getDom(id);
39680 body = document.createElement("div");
39683 //Roo.fly(body).addClass("x-tabs-item-body");
39684 Roo.fly(body).addClass("tab-pane");
39685 bodyEl.insertBefore(body, bodyEl.firstChild);
39689 createStripElements : function(stripEl, text, closable, tpl)
39691 var td = document.createElement("li"); // was td..
39692 td.className = 'nav-item';
39694 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
39697 stripEl.appendChild(td);
39699 td.className = "x-tabs-closable";
39700 if(!this.closeTpl){
39701 this.closeTpl = new Roo.Template(
39702 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
39703 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
39704 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
39707 var el = this.closeTpl.overwrite(td, {"text": text});
39708 var close = el.getElementsByTagName("div")[0];
39709 var inner = el.getElementsByTagName("em")[0];
39710 return {"el": el, "close": close, "inner": inner};
39713 // not sure what this is..
39714 // if(!this.tabTpl){
39715 //this.tabTpl = new Roo.Template(
39716 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
39717 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
39719 // this.tabTpl = new Roo.Template(
39720 // '<a href="#">' +
39721 // '<span unselectable="on"' +
39722 // (this.disableTooltips ? '' : ' title="{text}"') +
39723 // ' >{text}</span></a>'
39729 var template = tpl || this.tabTpl || false;
39732 template = new Roo.Template(
39733 Roo.bootstrap.version == 4 ?
39735 '<a class="nav-link" href="#" unselectable="on"' +
39736 (this.disableTooltips ? '' : ' title="{text}"') +
39739 '<a class="nav-link" href="#">' +
39740 '<span unselectable="on"' +
39741 (this.disableTooltips ? '' : ' title="{text}"') +
39742 ' >{text}</span></a>'
39747 switch (typeof(template)) {
39751 template = new Roo.Template(template);
39757 var el = template.overwrite(td, {"text": text});
39759 var inner = el.getElementsByTagName("span")[0];
39761 return {"el": el, "inner": inner};
39769 * @class Roo.TabPanelItem
39770 * @extends Roo.util.Observable
39771 * Represents an individual item (tab plus body) in a TabPanel.
39772 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
39773 * @param {String} id The id of this TabPanelItem
39774 * @param {String} text The text for the tab of this TabPanelItem
39775 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
39777 Roo.bootstrap.panel.TabItem = function(config){
39779 * The {@link Roo.TabPanel} this TabPanelItem belongs to
39780 * @type Roo.TabPanel
39782 this.tabPanel = config.panel;
39784 * The id for this TabPanelItem
39787 this.id = config.id;
39789 this.disabled = false;
39791 this.text = config.text;
39793 this.loaded = false;
39794 this.closable = config.closable;
39797 * The body element for this TabPanelItem.
39798 * @type Roo.Element
39800 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
39801 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
39802 this.bodyEl.setStyle("display", "block");
39803 this.bodyEl.setStyle("zoom", "1");
39804 //this.hideAction();
39806 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
39808 this.el = Roo.get(els.el);
39809 this.inner = Roo.get(els.inner, true);
39810 this.textEl = Roo.bootstrap.version == 4 ?
39811 this.el : Roo.get(this.el.dom.firstChild, true);
39813 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
39814 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
39817 // this.el.on("mousedown", this.onTabMouseDown, this);
39818 this.el.on("click", this.onTabClick, this);
39820 if(config.closable){
39821 var c = Roo.get(els.close, true);
39822 c.dom.title = this.closeText;
39823 c.addClassOnOver("close-over");
39824 c.on("click", this.closeClick, this);
39830 * Fires when this tab becomes the active tab.
39831 * @param {Roo.TabPanel} tabPanel The parent TabPanel
39832 * @param {Roo.TabPanelItem} this
39836 * @event beforeclose
39837 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
39838 * @param {Roo.TabPanelItem} this
39839 * @param {Object} e Set cancel to true on this object to cancel the close.
39841 "beforeclose": true,
39844 * Fires when this tab is closed.
39845 * @param {Roo.TabPanelItem} this
39849 * @event deactivate
39850 * Fires when this tab is no longer the active tab.
39851 * @param {Roo.TabPanel} tabPanel The parent TabPanel
39852 * @param {Roo.TabPanelItem} this
39854 "deactivate" : true
39856 this.hidden = false;
39858 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
39861 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
39863 purgeListeners : function(){
39864 Roo.util.Observable.prototype.purgeListeners.call(this);
39865 this.el.removeAllListeners();
39868 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
39871 this.status_node.addClass("active");
39874 this.tabPanel.stripWrap.repaint();
39876 this.fireEvent("activate", this.tabPanel, this);
39880 * Returns true if this tab is the active tab.
39881 * @return {Boolean}
39883 isActive : function(){
39884 return this.tabPanel.getActiveTab() == this;
39888 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
39891 this.status_node.removeClass("active");
39893 this.fireEvent("deactivate", this.tabPanel, this);
39896 hideAction : function(){
39897 this.bodyEl.hide();
39898 this.bodyEl.setStyle("position", "absolute");
39899 this.bodyEl.setLeft("-20000px");
39900 this.bodyEl.setTop("-20000px");
39903 showAction : function(){
39904 this.bodyEl.setStyle("position", "relative");
39905 this.bodyEl.setTop("");
39906 this.bodyEl.setLeft("");
39907 this.bodyEl.show();
39911 * Set the tooltip for the tab.
39912 * @param {String} tooltip The tab's tooltip
39914 setTooltip : function(text){
39915 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
39916 this.textEl.dom.qtip = text;
39917 this.textEl.dom.removeAttribute('title');
39919 this.textEl.dom.title = text;
39923 onTabClick : function(e){
39924 e.preventDefault();
39925 this.tabPanel.activate(this.id);
39928 onTabMouseDown : function(e){
39929 e.preventDefault();
39930 this.tabPanel.activate(this.id);
39933 getWidth : function(){
39934 return this.inner.getWidth();
39937 setWidth : function(width){
39938 var iwidth = width - this.linode.getPadding("lr");
39939 this.inner.setWidth(iwidth);
39940 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
39941 this.linode.setWidth(width);
39945 * Show or hide the tab
39946 * @param {Boolean} hidden True to hide or false to show.
39948 setHidden : function(hidden){
39949 this.hidden = hidden;
39950 this.linode.setStyle("display", hidden ? "none" : "");
39954 * Returns true if this tab is "hidden"
39955 * @return {Boolean}
39957 isHidden : function(){
39958 return this.hidden;
39962 * Returns the text for this tab
39965 getText : function(){
39969 autoSize : function(){
39970 //this.el.beginMeasure();
39971 this.textEl.setWidth(1);
39973 * #2804 [new] Tabs in Roojs
39974 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
39976 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
39977 //this.el.endMeasure();
39981 * Sets the text for the tab (Note: this also sets the tooltip text)
39982 * @param {String} text The tab's text and tooltip
39984 setText : function(text){
39986 this.textEl.update(text);
39987 this.setTooltip(text);
39988 //if(!this.tabPanel.resizeTabs){
39989 // this.autoSize();
39993 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
39995 activate : function(){
39996 this.tabPanel.activate(this.id);
40000 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
40002 disable : function(){
40003 if(this.tabPanel.active != this){
40004 this.disabled = true;
40005 this.status_node.addClass("disabled");
40010 * Enables this TabPanelItem if it was previously disabled.
40012 enable : function(){
40013 this.disabled = false;
40014 this.status_node.removeClass("disabled");
40018 * Sets the content for this TabPanelItem.
40019 * @param {String} content The content
40020 * @param {Boolean} loadScripts true to look for and load scripts
40022 setContent : function(content, loadScripts){
40023 this.bodyEl.update(content, loadScripts);
40027 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
40028 * @return {Roo.UpdateManager} The UpdateManager
40030 getUpdateManager : function(){
40031 return this.bodyEl.getUpdateManager();
40035 * Set a URL to be used to load the content for this TabPanelItem.
40036 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
40037 * @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)
40038 * @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)
40039 * @return {Roo.UpdateManager} The UpdateManager
40041 setUrl : function(url, params, loadOnce){
40042 if(this.refreshDelegate){
40043 this.un('activate', this.refreshDelegate);
40045 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
40046 this.on("activate", this.refreshDelegate);
40047 return this.bodyEl.getUpdateManager();
40051 _handleRefresh : function(url, params, loadOnce){
40052 if(!loadOnce || !this.loaded){
40053 var updater = this.bodyEl.getUpdateManager();
40054 updater.update(url, params, this._setLoaded.createDelegate(this));
40059 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
40060 * Will fail silently if the setUrl method has not been called.
40061 * This does not activate the panel, just updates its content.
40063 refresh : function(){
40064 if(this.refreshDelegate){
40065 this.loaded = false;
40066 this.refreshDelegate();
40071 _setLoaded : function(){
40072 this.loaded = true;
40076 closeClick : function(e){
40079 this.fireEvent("beforeclose", this, o);
40080 if(o.cancel !== true){
40081 this.tabPanel.removeTab(this.id);
40085 * The text displayed in the tooltip for the close icon.
40088 closeText : "Close this tab"
40091 * This script refer to:
40092 * Title: International Telephone Input
40093 * Author: Jack O'Connor
40094 * Code version: v12.1.12
40095 * Availability: https://github.com/jackocnr/intl-tel-input.git
40098 Roo.bootstrap.PhoneInputData = function() {
40101 "Afghanistan (افغانستان)",
40106 "Albania (Shqipëri)",
40111 "Algeria (الجزائر)",
40136 "Antigua and Barbuda",
40146 "Armenia (Հայաստան)",
40162 "Austria (Österreich)",
40167 "Azerbaijan (Azərbaycan)",
40177 "Bahrain (البحرين)",
40182 "Bangladesh (বাংলাদেশ)",
40192 "Belarus (Беларусь)",
40197 "Belgium (België)",
40227 "Bosnia and Herzegovina (Босна и Херцеговина)",
40242 "British Indian Ocean Territory",
40247 "British Virgin Islands",
40257 "Bulgaria (България)",
40267 "Burundi (Uburundi)",
40272 "Cambodia (កម្ពុជា)",
40277 "Cameroon (Cameroun)",
40286 ["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"]
40289 "Cape Verde (Kabu Verdi)",
40294 "Caribbean Netherlands",
40305 "Central African Republic (République centrafricaine)",
40325 "Christmas Island",
40331 "Cocos (Keeling) Islands",
40342 "Comoros (جزر القمر)",
40347 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
40352 "Congo (Republic) (Congo-Brazzaville)",
40372 "Croatia (Hrvatska)",
40393 "Czech Republic (Česká republika)",
40398 "Denmark (Danmark)",
40413 "Dominican Republic (República Dominicana)",
40417 ["809", "829", "849"]
40435 "Equatorial Guinea (Guinea Ecuatorial)",
40455 "Falkland Islands (Islas Malvinas)",
40460 "Faroe Islands (Føroyar)",
40481 "French Guiana (Guyane française)",
40486 "French Polynesia (Polynésie française)",
40501 "Georgia (საქართველო)",
40506 "Germany (Deutschland)",
40526 "Greenland (Kalaallit Nunaat)",
40563 "Guinea-Bissau (Guiné Bissau)",
40588 "Hungary (Magyarország)",
40593 "Iceland (Ísland)",
40613 "Iraq (العراق)",
40629 "Israel (ישראל)",
40656 "Jordan (الأردن)",
40661 "Kazakhstan (Казахстан)",
40682 "Kuwait (الكويت)",
40687 "Kyrgyzstan (Кыргызстан)",
40697 "Latvia (Latvija)",
40702 "Lebanon (لبنان)",
40717 "Libya (ليبيا)",
40727 "Lithuania (Lietuva)",
40742 "Macedonia (FYROM) (Македонија)",
40747 "Madagascar (Madagasikara)",
40777 "Marshall Islands",
40787 "Mauritania (موريتانيا)",
40792 "Mauritius (Moris)",
40813 "Moldova (Republica Moldova)",
40823 "Mongolia (Монгол)",
40828 "Montenegro (Crna Gora)",
40838 "Morocco (المغرب)",
40844 "Mozambique (Moçambique)",
40849 "Myanmar (Burma) (မြန်မာ)",
40854 "Namibia (Namibië)",
40869 "Netherlands (Nederland)",
40874 "New Caledonia (Nouvelle-Calédonie)",
40909 "North Korea (조선 민주주의 인민 공화국)",
40914 "Northern Mariana Islands",
40930 "Pakistan (پاکستان)",
40940 "Palestine (فلسطين)",
40950 "Papua New Guinea",
40992 "Réunion (La Réunion)",
40998 "Romania (România)",
41014 "Saint Barthélemy",
41025 "Saint Kitts and Nevis",
41035 "Saint Martin (Saint-Martin (partie française))",
41041 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
41046 "Saint Vincent and the Grenadines",
41061 "São Tomé and Príncipe (São Tomé e Príncipe)",
41066 "Saudi Arabia (المملكة العربية السعودية)",
41071 "Senegal (Sénégal)",
41101 "Slovakia (Slovensko)",
41106 "Slovenia (Slovenija)",
41116 "Somalia (Soomaaliya)",
41126 "South Korea (대한민국)",
41131 "South Sudan (جنوب السودان)",
41141 "Sri Lanka (ශ්රී ලංකාව)",
41146 "Sudan (السودان)",
41156 "Svalbard and Jan Mayen",
41167 "Sweden (Sverige)",
41172 "Switzerland (Schweiz)",
41177 "Syria (سوريا)",
41222 "Trinidad and Tobago",
41227 "Tunisia (تونس)",
41232 "Turkey (Türkiye)",
41242 "Turks and Caicos Islands",
41252 "U.S. Virgin Islands",
41262 "Ukraine (Україна)",
41267 "United Arab Emirates (الإمارات العربية المتحدة)",
41289 "Uzbekistan (Oʻzbekiston)",
41299 "Vatican City (Città del Vaticano)",
41310 "Vietnam (Việt Nam)",
41315 "Wallis and Futuna (Wallis-et-Futuna)",
41320 "Western Sahara (الصحراء الغربية)",
41326 "Yemen (اليمن)",
41350 * This script refer to:
41351 * Title: International Telephone Input
41352 * Author: Jack O'Connor
41353 * Code version: v12.1.12
41354 * Availability: https://github.com/jackocnr/intl-tel-input.git
41358 * @class Roo.bootstrap.PhoneInput
41359 * @extends Roo.bootstrap.TriggerField
41360 * An input with International dial-code selection
41362 * @cfg {String} defaultDialCode default '+852'
41363 * @cfg {Array} preferedCountries default []
41366 * Create a new PhoneInput.
41367 * @param {Object} config Configuration options
41370 Roo.bootstrap.PhoneInput = function(config) {
41371 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
41374 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
41376 listWidth: undefined,
41378 selectedClass: 'active',
41380 invalidClass : "has-warning",
41382 validClass: 'has-success',
41384 allowed: '0123456789',
41389 * @cfg {String} defaultDialCode The default dial code when initializing the input
41391 defaultDialCode: '+852',
41394 * @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
41396 preferedCountries: false,
41398 getAutoCreate : function()
41400 var data = Roo.bootstrap.PhoneInputData();
41401 var align = this.labelAlign || this.parentLabelAlign();
41404 this.allCountries = [];
41405 this.dialCodeMapping = [];
41407 for (var i = 0; i < data.length; i++) {
41409 this.allCountries[i] = {
41413 priority: c[3] || 0,
41414 areaCodes: c[4] || null
41416 this.dialCodeMapping[c[2]] = {
41419 priority: c[3] || 0,
41420 areaCodes: c[4] || null
41432 // type: 'number', -- do not use number - we get the flaky up/down arrows.
41433 maxlength: this.max_length,
41434 cls : 'form-control tel-input',
41435 autocomplete: 'new-password'
41438 var hiddenInput = {
41441 cls: 'hidden-tel-input'
41445 hiddenInput.name = this.name;
41448 if (this.disabled) {
41449 input.disabled = true;
41452 var flag_container = {
41469 cls: this.hasFeedback ? 'has-feedback' : '',
41475 cls: 'dial-code-holder',
41482 cls: 'roo-select2-container input-group',
41489 if (this.fieldLabel.length) {
41492 tooltip: 'This field is required'
41498 cls: 'control-label',
41504 html: this.fieldLabel
41507 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41513 if(this.indicatorpos == 'right') {
41514 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41521 if(align == 'left') {
41529 if(this.labelWidth > 12){
41530 label.style = "width: " + this.labelWidth + 'px';
41532 if(this.labelWidth < 13 && this.labelmd == 0){
41533 this.labelmd = this.labelWidth;
41535 if(this.labellg > 0){
41536 label.cls += ' col-lg-' + this.labellg;
41537 input.cls += ' col-lg-' + (12 - this.labellg);
41539 if(this.labelmd > 0){
41540 label.cls += ' col-md-' + this.labelmd;
41541 container.cls += ' col-md-' + (12 - this.labelmd);
41543 if(this.labelsm > 0){
41544 label.cls += ' col-sm-' + this.labelsm;
41545 container.cls += ' col-sm-' + (12 - this.labelsm);
41547 if(this.labelxs > 0){
41548 label.cls += ' col-xs-' + this.labelxs;
41549 container.cls += ' col-xs-' + (12 - this.labelxs);
41559 var settings = this;
41561 ['xs','sm','md','lg'].map(function(size){
41562 if (settings[size]) {
41563 cfg.cls += ' col-' + size + '-' + settings[size];
41567 this.store = new Roo.data.Store({
41568 proxy : new Roo.data.MemoryProxy({}),
41569 reader : new Roo.data.JsonReader({
41580 'name' : 'dialCode',
41584 'name' : 'priority',
41588 'name' : 'areaCodes',
41595 if(!this.preferedCountries) {
41596 this.preferedCountries = [
41603 var p = this.preferedCountries.reverse();
41606 for (var i = 0; i < p.length; i++) {
41607 for (var j = 0; j < this.allCountries.length; j++) {
41608 if(this.allCountries[j].iso2 == p[i]) {
41609 var t = this.allCountries[j];
41610 this.allCountries.splice(j,1);
41611 this.allCountries.unshift(t);
41617 this.store.proxy.data = {
41619 data: this.allCountries
41625 initEvents : function()
41628 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
41630 this.indicator = this.indicatorEl();
41631 this.flag = this.flagEl();
41632 this.dialCodeHolder = this.dialCodeHolderEl();
41634 this.trigger = this.el.select('div.flag-box',true).first();
41635 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
41640 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41641 _this.list.setWidth(lw);
41644 this.list.on('mouseover', this.onViewOver, this);
41645 this.list.on('mousemove', this.onViewMove, this);
41646 this.inputEl().on("keyup", this.onKeyUp, this);
41647 this.inputEl().on("keypress", this.onKeyPress, this);
41649 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
41651 this.view = new Roo.View(this.list, this.tpl, {
41652 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41655 this.view.on('click', this.onViewClick, this);
41656 this.setValue(this.defaultDialCode);
41659 onTriggerClick : function(e)
41661 Roo.log('trigger click');
41666 if(this.isExpanded()){
41668 this.hasFocus = false;
41670 this.store.load({});
41671 this.hasFocus = true;
41676 isExpanded : function()
41678 return this.list.isVisible();
41681 collapse : function()
41683 if(!this.isExpanded()){
41687 Roo.get(document).un('mousedown', this.collapseIf, this);
41688 Roo.get(document).un('mousewheel', this.collapseIf, this);
41689 this.fireEvent('collapse', this);
41693 expand : function()
41697 if(this.isExpanded() || !this.hasFocus){
41701 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
41702 this.list.setWidth(lw);
41705 this.restrictHeight();
41707 Roo.get(document).on('mousedown', this.collapseIf, this);
41708 Roo.get(document).on('mousewheel', this.collapseIf, this);
41710 this.fireEvent('expand', this);
41713 restrictHeight : function()
41715 this.list.alignTo(this.inputEl(), this.listAlign);
41716 this.list.alignTo(this.inputEl(), this.listAlign);
41719 onViewOver : function(e, t)
41721 if(this.inKeyMode){
41724 var item = this.view.findItemFromChild(t);
41727 var index = this.view.indexOf(item);
41728 this.select(index, false);
41733 onViewClick : function(view, doFocus, el, e)
41735 var index = this.view.getSelectedIndexes()[0];
41737 var r = this.store.getAt(index);
41740 this.onSelect(r, index);
41742 if(doFocus !== false && !this.blockFocus){
41743 this.inputEl().focus();
41747 onViewMove : function(e, t)
41749 this.inKeyMode = false;
41752 select : function(index, scrollIntoView)
41754 this.selectedIndex = index;
41755 this.view.select(index);
41756 if(scrollIntoView !== false){
41757 var el = this.view.getNode(index);
41759 this.list.scrollChildIntoView(el, false);
41764 createList : function()
41766 this.list = Roo.get(document.body).createChild({
41768 cls: 'typeahead typeahead-long dropdown-menu tel-list',
41769 style: 'display:none'
41772 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
41775 collapseIf : function(e)
41777 var in_combo = e.within(this.el);
41778 var in_list = e.within(this.list);
41779 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
41781 if (in_combo || in_list || is_list) {
41787 onSelect : function(record, index)
41789 if(this.fireEvent('beforeselect', this, record, index) !== false){
41791 this.setFlagClass(record.data.iso2);
41792 this.setDialCode(record.data.dialCode);
41793 this.hasFocus = false;
41795 this.fireEvent('select', this, record, index);
41799 flagEl : function()
41801 var flag = this.el.select('div.flag',true).first();
41808 dialCodeHolderEl : function()
41810 var d = this.el.select('input.dial-code-holder',true).first();
41817 setDialCode : function(v)
41819 this.dialCodeHolder.dom.value = '+'+v;
41822 setFlagClass : function(n)
41824 this.flag.dom.className = 'flag '+n;
41827 getValue : function()
41829 var v = this.inputEl().getValue();
41830 if(this.dialCodeHolder) {
41831 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
41836 setValue : function(v)
41838 var d = this.getDialCode(v);
41840 //invalid dial code
41841 if(v.length == 0 || !d || d.length == 0) {
41843 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
41844 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41850 this.setFlagClass(this.dialCodeMapping[d].iso2);
41851 this.setDialCode(d);
41852 this.inputEl().dom.value = v.replace('+'+d,'');
41853 this.hiddenEl().dom.value = this.getValue();
41858 getDialCode : function(v)
41862 if (v.length == 0) {
41863 return this.dialCodeHolder.dom.value;
41867 if (v.charAt(0) != "+") {
41870 var numericChars = "";
41871 for (var i = 1; i < v.length; i++) {
41872 var c = v.charAt(i);
41875 if (this.dialCodeMapping[numericChars]) {
41876 dialCode = v.substr(1, i);
41878 if (numericChars.length == 4) {
41888 this.setValue(this.defaultDialCode);
41892 hiddenEl : function()
41894 return this.el.select('input.hidden-tel-input',true).first();
41897 // after setting val
41898 onKeyUp : function(e){
41899 this.setValue(this.getValue());
41902 onKeyPress : function(e){
41903 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
41910 * @class Roo.bootstrap.MoneyField
41911 * @extends Roo.bootstrap.ComboBox
41912 * Bootstrap MoneyField class
41915 * Create a new MoneyField.
41916 * @param {Object} config Configuration options
41919 Roo.bootstrap.MoneyField = function(config) {
41921 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
41925 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
41928 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
41930 allowDecimals : true,
41932 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
41934 decimalSeparator : ".",
41936 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
41938 decimalPrecision : 0,
41940 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
41942 allowNegative : true,
41944 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
41948 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
41950 minValue : Number.NEGATIVE_INFINITY,
41952 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
41954 maxValue : Number.MAX_VALUE,
41956 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
41958 minText : "The minimum value for this field is {0}",
41960 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
41962 maxText : "The maximum value for this field is {0}",
41964 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
41965 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
41967 nanText : "{0} is not a valid number",
41969 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
41973 * @cfg {String} defaults currency of the MoneyField
41974 * value should be in lkey
41976 defaultCurrency : false,
41978 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
41980 thousandsDelimiter : false,
41982 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
41993 getAutoCreate : function()
41995 var align = this.labelAlign || this.parentLabelAlign();
42007 cls : 'form-control roo-money-amount-input',
42008 autocomplete: 'new-password'
42011 var hiddenInput = {
42015 cls: 'hidden-number-input'
42018 if(this.max_length) {
42019 input.maxlength = this.max_length;
42023 hiddenInput.name = this.name;
42026 if (this.disabled) {
42027 input.disabled = true;
42030 var clg = 12 - this.inputlg;
42031 var cmd = 12 - this.inputmd;
42032 var csm = 12 - this.inputsm;
42033 var cxs = 12 - this.inputxs;
42037 cls : 'row roo-money-field',
42041 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
42045 cls: 'roo-select2-container input-group',
42049 cls : 'form-control roo-money-currency-input',
42050 autocomplete: 'new-password',
42052 name : this.currencyName
42056 cls : 'input-group-addon',
42070 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
42074 cls: this.hasFeedback ? 'has-feedback' : '',
42085 if (this.fieldLabel.length) {
42088 tooltip: 'This field is required'
42094 cls: 'control-label',
42100 html: this.fieldLabel
42103 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42109 if(this.indicatorpos == 'right') {
42110 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42117 if(align == 'left') {
42125 if(this.labelWidth > 12){
42126 label.style = "width: " + this.labelWidth + 'px';
42128 if(this.labelWidth < 13 && this.labelmd == 0){
42129 this.labelmd = this.labelWidth;
42131 if(this.labellg > 0){
42132 label.cls += ' col-lg-' + this.labellg;
42133 input.cls += ' col-lg-' + (12 - this.labellg);
42135 if(this.labelmd > 0){
42136 label.cls += ' col-md-' + this.labelmd;
42137 container.cls += ' col-md-' + (12 - this.labelmd);
42139 if(this.labelsm > 0){
42140 label.cls += ' col-sm-' + this.labelsm;
42141 container.cls += ' col-sm-' + (12 - this.labelsm);
42143 if(this.labelxs > 0){
42144 label.cls += ' col-xs-' + this.labelxs;
42145 container.cls += ' col-xs-' + (12 - this.labelxs);
42156 var settings = this;
42158 ['xs','sm','md','lg'].map(function(size){
42159 if (settings[size]) {
42160 cfg.cls += ' col-' + size + '-' + settings[size];
42167 initEvents : function()
42169 this.indicator = this.indicatorEl();
42171 this.initCurrencyEvent();
42173 this.initNumberEvent();
42176 initCurrencyEvent : function()
42179 throw "can not find store for combo";
42182 this.store = Roo.factory(this.store, Roo.data);
42183 this.store.parent = this;
42187 this.triggerEl = this.el.select('.input-group-addon', true).first();
42189 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
42194 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42195 _this.list.setWidth(lw);
42198 this.list.on('mouseover', this.onViewOver, this);
42199 this.list.on('mousemove', this.onViewMove, this);
42200 this.list.on('scroll', this.onViewScroll, this);
42203 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
42206 this.view = new Roo.View(this.list, this.tpl, {
42207 singleSelect:true, store: this.store, selectedClass: this.selectedClass
42210 this.view.on('click', this.onViewClick, this);
42212 this.store.on('beforeload', this.onBeforeLoad, this);
42213 this.store.on('load', this.onLoad, this);
42214 this.store.on('loadexception', this.onLoadException, this);
42216 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
42217 "up" : function(e){
42218 this.inKeyMode = true;
42222 "down" : function(e){
42223 if(!this.isExpanded()){
42224 this.onTriggerClick();
42226 this.inKeyMode = true;
42231 "enter" : function(e){
42234 if(this.fireEvent("specialkey", this, e)){
42235 this.onViewClick(false);
42241 "esc" : function(e){
42245 "tab" : function(e){
42248 if(this.fireEvent("specialkey", this, e)){
42249 this.onViewClick(false);
42257 doRelay : function(foo, bar, hname){
42258 if(hname == 'down' || this.scope.isExpanded()){
42259 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
42267 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
42271 initNumberEvent : function(e)
42273 this.inputEl().on("keydown" , this.fireKey, this);
42274 this.inputEl().on("focus", this.onFocus, this);
42275 this.inputEl().on("blur", this.onBlur, this);
42277 this.inputEl().relayEvent('keyup', this);
42279 if(this.indicator){
42280 this.indicator.addClass('invisible');
42283 this.originalValue = this.getValue();
42285 if(this.validationEvent == 'keyup'){
42286 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
42287 this.inputEl().on('keyup', this.filterValidation, this);
42289 else if(this.validationEvent !== false){
42290 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
42293 if(this.selectOnFocus){
42294 this.on("focus", this.preFocus, this);
42297 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
42298 this.inputEl().on("keypress", this.filterKeys, this);
42300 this.inputEl().relayEvent('keypress', this);
42303 var allowed = "0123456789";
42305 if(this.allowDecimals){
42306 allowed += this.decimalSeparator;
42309 if(this.allowNegative){
42313 if(this.thousandsDelimiter) {
42317 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
42319 var keyPress = function(e){
42321 var k = e.getKey();
42323 var c = e.getCharCode();
42326 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
42327 allowed.indexOf(String.fromCharCode(c)) === -1
42333 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
42337 if(allowed.indexOf(String.fromCharCode(c)) === -1){
42342 this.inputEl().on("keypress", keyPress, this);
42346 onTriggerClick : function(e)
42353 this.loadNext = false;
42355 if(this.isExpanded()){
42360 this.hasFocus = true;
42362 if(this.triggerAction == 'all') {
42363 this.doQuery(this.allQuery, true);
42367 this.doQuery(this.getRawValue());
42370 getCurrency : function()
42372 var v = this.currencyEl().getValue();
42377 restrictHeight : function()
42379 this.list.alignTo(this.currencyEl(), this.listAlign);
42380 this.list.alignTo(this.currencyEl(), this.listAlign);
42383 onViewClick : function(view, doFocus, el, e)
42385 var index = this.view.getSelectedIndexes()[0];
42387 var r = this.store.getAt(index);
42390 this.onSelect(r, index);
42394 onSelect : function(record, index){
42396 if(this.fireEvent('beforeselect', this, record, index) !== false){
42398 this.setFromCurrencyData(index > -1 ? record.data : false);
42402 this.fireEvent('select', this, record, index);
42406 setFromCurrencyData : function(o)
42410 this.lastCurrency = o;
42412 if (this.currencyField) {
42413 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
42415 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
42418 this.lastSelectionText = currency;
42420 //setting default currency
42421 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
42422 this.setCurrency(this.defaultCurrency);
42426 this.setCurrency(currency);
42429 setFromData : function(o)
42433 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
42435 this.setFromCurrencyData(c);
42440 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
42442 Roo.log('no value set for '+ (this.name ? this.name : this.id));
42445 this.setValue(value);
42449 setCurrency : function(v)
42451 this.currencyValue = v;
42454 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
42459 setValue : function(v)
42461 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
42467 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
42469 this.inputEl().dom.value = (v == '') ? '' :
42470 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
42472 if(!this.allowZero && v === '0') {
42473 this.hiddenEl().dom.value = '';
42474 this.inputEl().dom.value = '';
42481 getRawValue : function()
42483 var v = this.inputEl().getValue();
42488 getValue : function()
42490 return this.fixPrecision(this.parseValue(this.getRawValue()));
42493 parseValue : function(value)
42495 if(this.thousandsDelimiter) {
42497 r = new RegExp(",", "g");
42498 value = value.replace(r, "");
42501 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
42502 return isNaN(value) ? '' : value;
42506 fixPrecision : function(value)
42508 if(this.thousandsDelimiter) {
42510 r = new RegExp(",", "g");
42511 value = value.replace(r, "");
42514 var nan = isNaN(value);
42516 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
42517 return nan ? '' : value;
42519 return parseFloat(value).toFixed(this.decimalPrecision);
42522 decimalPrecisionFcn : function(v)
42524 return Math.floor(v);
42527 validateValue : function(value)
42529 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
42533 var num = this.parseValue(value);
42536 this.markInvalid(String.format(this.nanText, value));
42540 if(num < this.minValue){
42541 this.markInvalid(String.format(this.minText, this.minValue));
42545 if(num > this.maxValue){
42546 this.markInvalid(String.format(this.maxText, this.maxValue));
42553 validate : function()
42555 if(this.disabled || this.allowBlank){
42560 var currency = this.getCurrency();
42562 if(this.validateValue(this.getRawValue()) && currency.length){
42567 this.markInvalid();
42571 getName: function()
42576 beforeBlur : function()
42582 var v = this.parseValue(this.getRawValue());
42589 onBlur : function()
42593 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
42594 //this.el.removeClass(this.focusClass);
42597 this.hasFocus = false;
42599 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
42603 var v = this.getValue();
42605 if(String(v) !== String(this.startValue)){
42606 this.fireEvent('change', this, v, this.startValue);
42609 this.fireEvent("blur", this);
42612 inputEl : function()
42614 return this.el.select('.roo-money-amount-input', true).first();
42617 currencyEl : function()
42619 return this.el.select('.roo-money-currency-input', true).first();
42622 hiddenEl : function()
42624 return this.el.select('input.hidden-number-input',true).first();
42628 * @class Roo.bootstrap.BezierSignature
42629 * @extends Roo.bootstrap.Component
42630 * Bootstrap BezierSignature class
42631 * This script refer to:
42632 * Title: Signature Pad
42634 * Availability: https://github.com/szimek/signature_pad
42637 * Create a new BezierSignature
42638 * @param {Object} config The config object
42641 Roo.bootstrap.BezierSignature = function(config){
42642 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
42648 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
42655 mouse_btn_down: true,
42658 * @cfg {int} canvas height
42660 canvas_height: '200px',
42663 * @cfg {float|function} Radius of a single dot.
42668 * @cfg {float} Minimum width of a line. Defaults to 0.5.
42673 * @cfg {float} Maximum width of a line. Defaults to 2.5.
42678 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
42683 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
42688 * @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.
42690 bg_color: 'rgba(0, 0, 0, 0)',
42693 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
42695 dot_color: 'black',
42698 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
42700 velocity_filter_weight: 0.7,
42703 * @cfg {function} Callback when stroke begin.
42708 * @cfg {function} Callback when stroke end.
42712 getAutoCreate : function()
42714 var cls = 'roo-signature column';
42717 cls += ' ' + this.cls;
42727 for(var i = 0; i < col_sizes.length; i++) {
42728 if(this[col_sizes[i]]) {
42729 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
42739 cls: 'roo-signature-body',
42743 cls: 'roo-signature-body-canvas',
42744 height: this.canvas_height,
42745 width: this.canvas_width
42752 style: 'display: none'
42760 initEvents: function()
42762 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
42764 var canvas = this.canvasEl();
42766 // mouse && touch event swapping...
42767 canvas.dom.style.touchAction = 'none';
42768 canvas.dom.style.msTouchAction = 'none';
42770 this.mouse_btn_down = false;
42771 canvas.on('mousedown', this._handleMouseDown, this);
42772 canvas.on('mousemove', this._handleMouseMove, this);
42773 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
42775 if (window.PointerEvent) {
42776 canvas.on('pointerdown', this._handleMouseDown, this);
42777 canvas.on('pointermove', this._handleMouseMove, this);
42778 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
42781 if ('ontouchstart' in window) {
42782 canvas.on('touchstart', this._handleTouchStart, this);
42783 canvas.on('touchmove', this._handleTouchMove, this);
42784 canvas.on('touchend', this._handleTouchEnd, this);
42787 Roo.EventManager.onWindowResize(this.resize, this, true);
42789 // file input event
42790 this.fileEl().on('change', this.uploadImage, this);
42797 resize: function(){
42799 var canvas = this.canvasEl().dom;
42800 var ctx = this.canvasElCtx();
42801 var img_data = false;
42803 if(canvas.width > 0) {
42804 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
42806 // setting canvas width will clean img data
42809 var style = window.getComputedStyle ?
42810 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
42812 var padding_left = parseInt(style.paddingLeft) || 0;
42813 var padding_right = parseInt(style.paddingRight) || 0;
42815 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
42818 ctx.putImageData(img_data, 0, 0);
42822 _handleMouseDown: function(e)
42824 if (e.browserEvent.which === 1) {
42825 this.mouse_btn_down = true;
42826 this.strokeBegin(e);
42830 _handleMouseMove: function (e)
42832 if (this.mouse_btn_down) {
42833 this.strokeMoveUpdate(e);
42837 _handleMouseUp: function (e)
42839 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
42840 this.mouse_btn_down = false;
42845 _handleTouchStart: function (e) {
42847 e.preventDefault();
42848 if (e.browserEvent.targetTouches.length === 1) {
42849 // var touch = e.browserEvent.changedTouches[0];
42850 // this.strokeBegin(touch);
42852 this.strokeBegin(e); // assume e catching the correct xy...
42856 _handleTouchMove: function (e) {
42857 e.preventDefault();
42858 // var touch = event.targetTouches[0];
42859 // _this._strokeMoveUpdate(touch);
42860 this.strokeMoveUpdate(e);
42863 _handleTouchEnd: function (e) {
42864 var wasCanvasTouched = e.target === this.canvasEl().dom;
42865 if (wasCanvasTouched) {
42866 e.preventDefault();
42867 // var touch = event.changedTouches[0];
42868 // _this._strokeEnd(touch);
42873 reset: function () {
42874 this._lastPoints = [];
42875 this._lastVelocity = 0;
42876 this._lastWidth = (this.min_width + this.max_width) / 2;
42877 this.canvasElCtx().fillStyle = this.dot_color;
42880 strokeMoveUpdate: function(e)
42882 this.strokeUpdate(e);
42884 if (this.throttle) {
42885 this.throttleStroke(this.strokeUpdate, this.throttle);
42888 this.strokeUpdate(e);
42892 strokeBegin: function(e)
42894 var newPointGroup = {
42895 color: this.dot_color,
42899 if (typeof this.onBegin === 'function') {
42903 this.curve_data.push(newPointGroup);
42905 this.strokeUpdate(e);
42908 strokeUpdate: function(e)
42910 var rect = this.canvasEl().dom.getBoundingClientRect();
42911 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
42912 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
42913 var lastPoints = lastPointGroup.points;
42914 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
42915 var isLastPointTooClose = lastPoint
42916 ? point.distanceTo(lastPoint) <= this.min_distance
42918 var color = lastPointGroup.color;
42919 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
42920 var curve = this.addPoint(point);
42922 this.drawDot({color: color, point: point});
42925 this.drawCurve({color: color, curve: curve});
42935 strokeEnd: function(e)
42937 this.strokeUpdate(e);
42938 if (typeof this.onEnd === 'function') {
42943 addPoint: function (point) {
42944 var _lastPoints = this._lastPoints;
42945 _lastPoints.push(point);
42946 if (_lastPoints.length > 2) {
42947 if (_lastPoints.length === 3) {
42948 _lastPoints.unshift(_lastPoints[0]);
42950 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
42951 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
42952 _lastPoints.shift();
42958 calculateCurveWidths: function (startPoint, endPoint) {
42959 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
42960 (1 - this.velocity_filter_weight) * this._lastVelocity;
42962 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
42965 start: this._lastWidth
42968 this._lastVelocity = velocity;
42969 this._lastWidth = newWidth;
42973 drawDot: function (_a) {
42974 var color = _a.color, point = _a.point;
42975 var ctx = this.canvasElCtx();
42976 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
42978 this.drawCurveSegment(point.x, point.y, width);
42980 ctx.fillStyle = color;
42984 drawCurve: function (_a) {
42985 var color = _a.color, curve = _a.curve;
42986 var ctx = this.canvasElCtx();
42987 var widthDelta = curve.endWidth - curve.startWidth;
42988 var drawSteps = Math.floor(curve.length()) * 2;
42990 ctx.fillStyle = color;
42991 for (var i = 0; i < drawSteps; i += 1) {
42992 var t = i / drawSteps;
42998 var x = uuu * curve.startPoint.x;
42999 x += 3 * uu * t * curve.control1.x;
43000 x += 3 * u * tt * curve.control2.x;
43001 x += ttt * curve.endPoint.x;
43002 var y = uuu * curve.startPoint.y;
43003 y += 3 * uu * t * curve.control1.y;
43004 y += 3 * u * tt * curve.control2.y;
43005 y += ttt * curve.endPoint.y;
43006 var width = curve.startWidth + ttt * widthDelta;
43007 this.drawCurveSegment(x, y, width);
43013 drawCurveSegment: function (x, y, width) {
43014 var ctx = this.canvasElCtx();
43016 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
43017 this.is_empty = false;
43022 var ctx = this.canvasElCtx();
43023 var canvas = this.canvasEl().dom;
43024 ctx.fillStyle = this.bg_color;
43025 ctx.clearRect(0, 0, canvas.width, canvas.height);
43026 ctx.fillRect(0, 0, canvas.width, canvas.height);
43027 this.curve_data = [];
43029 this.is_empty = true;
43034 return this.el.select('input',true).first();
43037 canvasEl: function()
43039 return this.el.select('canvas',true).first();
43042 canvasElCtx: function()
43044 return this.el.select('canvas',true).first().dom.getContext('2d');
43047 getImage: function(type)
43049 if(this.is_empty) {
43054 return this.canvasEl().dom.toDataURL('image/'+type, 1);
43057 drawFromImage: function(img_src)
43059 var img = new Image();
43061 img.onload = function(){
43062 this.canvasElCtx().drawImage(img, 0, 0);
43067 this.is_empty = false;
43070 selectImage: function()
43072 this.fileEl().dom.click();
43075 uploadImage: function(e)
43077 var reader = new FileReader();
43079 reader.onload = function(e){
43080 var img = new Image();
43081 img.onload = function(){
43083 this.canvasElCtx().drawImage(img, 0, 0);
43085 img.src = e.target.result;
43088 reader.readAsDataURL(e.target.files[0]);
43091 // Bezier Point Constructor
43092 Point: (function () {
43093 function Point(x, y, time) {
43096 this.time = time || Date.now();
43098 Point.prototype.distanceTo = function (start) {
43099 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
43101 Point.prototype.equals = function (other) {
43102 return this.x === other.x && this.y === other.y && this.time === other.time;
43104 Point.prototype.velocityFrom = function (start) {
43105 return this.time !== start.time
43106 ? this.distanceTo(start) / (this.time - start.time)
43113 // Bezier Constructor
43114 Bezier: (function () {
43115 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
43116 this.startPoint = startPoint;
43117 this.control2 = control2;
43118 this.control1 = control1;
43119 this.endPoint = endPoint;
43120 this.startWidth = startWidth;
43121 this.endWidth = endWidth;
43123 Bezier.fromPoints = function (points, widths, scope) {
43124 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
43125 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
43126 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
43128 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
43129 var dx1 = s1.x - s2.x;
43130 var dy1 = s1.y - s2.y;
43131 var dx2 = s2.x - s3.x;
43132 var dy2 = s2.y - s3.y;
43133 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
43134 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
43135 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
43136 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
43137 var dxm = m1.x - m2.x;
43138 var dym = m1.y - m2.y;
43139 var k = l2 / (l1 + l2);
43140 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
43141 var tx = s2.x - cm.x;
43142 var ty = s2.y - cm.y;
43144 c1: new scope.Point(m1.x + tx, m1.y + ty),
43145 c2: new scope.Point(m2.x + tx, m2.y + ty)
43148 Bezier.prototype.length = function () {
43153 for (var i = 0; i <= steps; i += 1) {
43155 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
43156 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
43158 var xdiff = cx - px;
43159 var ydiff = cy - py;
43160 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
43167 Bezier.prototype.point = function (t, start, c1, c2, end) {
43168 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
43169 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
43170 + (3.0 * c2 * (1.0 - t) * t * t)
43171 + (end * t * t * t);
43176 throttleStroke: function(fn, wait) {
43177 if (wait === void 0) { wait = 250; }
43179 var timeout = null;
43183 var later = function () {
43184 previous = Date.now();
43186 result = fn.apply(storedContext, storedArgs);
43188 storedContext = null;
43192 return function wrapper() {
43194 for (var _i = 0; _i < arguments.length; _i++) {
43195 args[_i] = arguments[_i];
43197 var now = Date.now();
43198 var remaining = wait - (now - previous);
43199 storedContext = this;
43201 if (remaining <= 0 || remaining > wait) {
43203 clearTimeout(timeout);
43207 result = fn.apply(storedContext, storedArgs);
43209 storedContext = null;
43213 else if (!timeout) {
43214 timeout = window.setTimeout(later, remaining);