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 ];
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) {
2357 var pt = this.getDropPoint(e, n, dd);
2358 var insertAt = (n == this.bodyEl.dom) ? this.items.length : n.nodeIndex;
2359 if (pt == "below") {
2362 for (var i = 0; i < this.items.length; i++) {
2363 var r = this.items[i];
2364 //var dup = this.store.getById(r.id);
2365 if (dup && (dd != this.dragZone)) {
2366 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
2369 this.store.insert(insertAt++, r.copy());
2371 data.source.isDirtyFlag = true;
2373 this.store.insert(insertAt++, r);
2375 this.isDirtyFlag = true;
2378 this.dragZone.cachedTarget = null;
2382 /** Decide whether to drop above or below a View node. */
2383 getDropPoint : function(e, n, dd)
2388 if (n == this.bodyEl.dom) {
2391 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
2392 var c = t + (b - t) / 2;
2393 var y = Roo.lib.Event.getPageY(e);
2400 onToggleCollapse : function(e)
2402 if (this.collapsed) {
2403 this.el.select('.roo-collapse-toggle').removeClass('collapsed');
2404 this.el.select('.roo-collapsable').addClass('show');
2405 this.collapsed = false;
2408 this.el.select('.roo-collapse-toggle').addClass('collapsed');
2409 this.el.select('.roo-collapsable').removeClass('show');
2410 this.collapsed = true;
2414 dropPlaceHolder: function (action, where_ar, data)
2416 if (this.dropEl === false) {
2417 this.dropEl = Roo.DomHelper.append(this.bodyEl, {
2421 this.dropEl.removeClass(['d-none', 'd-block']);
2422 if (action == 'hide') {
2424 this.dropEl.addClass('d-none');
2427 var cardel = where_ar[0].el.dom;
2429 this.dropEl.dom.parentNode.removeChild(this.dropEl.dom);
2430 if (where_ar[1] == 'above') {
2431 cardel.parentNode.insertBefore(this.dropEl.dom, cardel);
2432 } else if (cardel.nextSibling) {
2433 cardel.parentNode.insertBefore(this.dropEl.dom,cardel.nextSibling);
2435 cardel.parentNode.append(this.dropEl.dom);
2437 this.dropEl.addClass('d-block roo-card-dropzone');
2439 this.dropEl.setHeight( Roo.get(data.ddel).getHeight() );
2453 * Card header - holder for the card header elements.
2458 * @class Roo.bootstrap.CardHeader
2459 * @extends Roo.bootstrap.Element
2460 * Bootstrap CardHeader class
2462 * Create a new Card Header - that you can embed children into
2463 * @param {Object} config The config object
2466 Roo.bootstrap.CardHeader = function(config){
2467 Roo.bootstrap.CardHeader.superclass.constructor.call(this, config);
2470 Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element, {
2473 container_method : 'getCardHeader'
2486 * Card header - holder for the card header elements.
2491 * @class Roo.bootstrap.CardImageTop
2492 * @extends Roo.bootstrap.Element
2493 * Bootstrap CardImageTop class
2495 * Create a new Card Image Top container
2496 * @param {Object} config The config object
2499 Roo.bootstrap.CardImageTop = function(config){
2500 Roo.bootstrap.CardImageTop.superclass.constructor.call(this, config);
2503 Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element, {
2506 container_method : 'getCardImageTop'
2524 * @class Roo.bootstrap.Img
2525 * @extends Roo.bootstrap.Component
2526 * Bootstrap Img class
2527 * @cfg {Boolean} imgResponsive false | true
2528 * @cfg {String} border rounded | circle | thumbnail
2529 * @cfg {String} src image source
2530 * @cfg {String} alt image alternative text
2531 * @cfg {String} href a tag href
2532 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
2533 * @cfg {String} xsUrl xs image source
2534 * @cfg {String} smUrl sm image source
2535 * @cfg {String} mdUrl md image source
2536 * @cfg {String} lgUrl lg image source
2539 * Create a new Input
2540 * @param {Object} config The config object
2543 Roo.bootstrap.Img = function(config){
2544 Roo.bootstrap.Img.superclass.constructor.call(this, config);
2550 * The img click event for the img.
2551 * @param {Roo.EventObject} e
2557 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
2559 imgResponsive: true,
2569 getAutoCreate : function()
2571 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2572 return this.createSingleImg();
2577 cls: 'roo-image-responsive-group',
2582 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
2584 if(!_this[size + 'Url']){
2590 cls: (_this.imgResponsive) ? 'img-responsive' : '',
2591 html: _this.html || cfg.html,
2592 src: _this[size + 'Url']
2595 img.cls += ' roo-image-responsive-' + size;
2597 var s = ['xs', 'sm', 'md', 'lg'];
2599 s.splice(s.indexOf(size), 1);
2601 Roo.each(s, function(ss){
2602 img.cls += ' hidden-' + ss;
2605 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
2606 cfg.cls += ' img-' + _this.border;
2610 cfg.alt = _this.alt;
2623 a.target = _this.target;
2627 cfg.cn.push((_this.href) ? a : img);
2634 createSingleImg : function()
2638 cls: (this.imgResponsive) ? 'img-responsive' : '',
2640 src : 'about:blank' // just incase src get's set to undefined?!?
2643 cfg.html = this.html || cfg.html;
2645 cfg.src = this.src || cfg.src;
2647 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
2648 cfg.cls += ' img-' + this.border;
2665 a.target = this.target;
2670 return (this.href) ? a : cfg;
2673 initEvents: function()
2676 this.el.on('click', this.onClick, this);
2681 onClick : function(e)
2683 Roo.log('img onclick');
2684 this.fireEvent('click', this, e);
2687 * Sets the url of the image - used to update it
2688 * @param {String} url the url of the image
2691 setSrc : function(url)
2695 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2696 this.el.dom.src = url;
2700 this.el.select('img', true).first().dom.src = url;
2716 * @class Roo.bootstrap.Link
2717 * @extends Roo.bootstrap.Component
2718 * Bootstrap Link Class
2719 * @cfg {String} alt image alternative text
2720 * @cfg {String} href a tag href
2721 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
2722 * @cfg {String} html the content of the link.
2723 * @cfg {String} anchor name for the anchor link
2724 * @cfg {String} fa - favicon
2726 * @cfg {Boolean} preventDefault (true | false) default false
2730 * Create a new Input
2731 * @param {Object} config The config object
2734 Roo.bootstrap.Link = function(config){
2735 Roo.bootstrap.Link.superclass.constructor.call(this, config);
2741 * The img click event for the img.
2742 * @param {Roo.EventObject} e
2748 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
2752 preventDefault: false,
2758 getAutoCreate : function()
2760 var html = this.html || '';
2762 if (this.fa !== false) {
2763 html = '<i class="fa fa-' + this.fa + '"></i>';
2768 // anchor's do not require html/href...
2769 if (this.anchor === false) {
2771 cfg.href = this.href || '#';
2773 cfg.name = this.anchor;
2774 if (this.html !== false || this.fa !== false) {
2777 if (this.href !== false) {
2778 cfg.href = this.href;
2782 if(this.alt !== false){
2787 if(this.target !== false) {
2788 cfg.target = this.target;
2794 initEvents: function() {
2796 if(!this.href || this.preventDefault){
2797 this.el.on('click', this.onClick, this);
2801 onClick : function(e)
2803 if(this.preventDefault){
2806 //Roo.log('img onclick');
2807 this.fireEvent('click', this, e);
2820 * @class Roo.bootstrap.Header
2821 * @extends Roo.bootstrap.Component
2822 * Bootstrap Header class
2823 * @cfg {String} html content of header
2824 * @cfg {Number} level (1|2|3|4|5|6) default 1
2827 * Create a new Header
2828 * @param {Object} config The config object
2832 Roo.bootstrap.Header = function(config){
2833 Roo.bootstrap.Header.superclass.constructor.call(this, config);
2836 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
2844 getAutoCreate : function(){
2849 tag: 'h' + (1 *this.level),
2850 html: this.html || ''
2862 * Ext JS Library 1.1.1
2863 * Copyright(c) 2006-2007, Ext JS, LLC.
2865 * Originally Released Under LGPL - original licence link has changed is not relivant.
2868 * <script type="text/javascript">
2872 * @class Roo.bootstrap.MenuMgr
2873 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
2876 Roo.bootstrap.MenuMgr = function(){
2877 var menus, active, groups = {}, attached = false, lastShow = new Date();
2879 // private - called when first menu is created
2882 active = new Roo.util.MixedCollection();
2883 Roo.get(document).addKeyListener(27, function(){
2884 if(active.length > 0){
2892 if(active && active.length > 0){
2893 var c = active.clone();
2903 if(active.length < 1){
2904 Roo.get(document).un("mouseup", onMouseDown);
2912 var last = active.last();
2913 lastShow = new Date();
2916 Roo.get(document).on("mouseup", onMouseDown);
2921 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
2922 m.parentMenu.activeChild = m;
2923 }else if(last && last.isVisible()){
2924 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
2929 function onBeforeHide(m){
2931 m.activeChild.hide();
2933 if(m.autoHideTimer){
2934 clearTimeout(m.autoHideTimer);
2935 delete m.autoHideTimer;
2940 function onBeforeShow(m){
2941 var pm = m.parentMenu;
2942 if(!pm && !m.allowOtherMenus){
2944 }else if(pm && pm.activeChild && active != m){
2945 pm.activeChild.hide();
2949 // private this should really trigger on mouseup..
2950 function onMouseDown(e){
2951 Roo.log("on Mouse Up");
2953 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
2954 Roo.log("MenuManager hideAll");
2963 function onBeforeCheck(mi, state){
2965 var g = groups[mi.group];
2966 for(var i = 0, l = g.length; i < l; i++){
2968 g[i].setChecked(false);
2977 * Hides all menus that are currently visible
2979 hideAll : function(){
2984 register : function(menu){
2988 menus[menu.id] = menu;
2989 menu.on("beforehide", onBeforeHide);
2990 menu.on("hide", onHide);
2991 menu.on("beforeshow", onBeforeShow);
2992 menu.on("show", onShow);
2994 if(g && menu.events["checkchange"]){
2998 groups[g].push(menu);
2999 menu.on("checkchange", onCheck);
3004 * Returns a {@link Roo.menu.Menu} object
3005 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
3006 * be used to generate and return a new Menu instance.
3008 get : function(menu){
3009 if(typeof menu == "string"){ // menu id
3011 }else if(menu.events){ // menu instance
3014 /*else if(typeof menu.length == 'number'){ // array of menu items?
3015 return new Roo.bootstrap.Menu({items:menu});
3016 }else{ // otherwise, must be a config
3017 return new Roo.bootstrap.Menu(menu);
3024 unregister : function(menu){
3025 delete menus[menu.id];
3026 menu.un("beforehide", onBeforeHide);
3027 menu.un("hide", onHide);
3028 menu.un("beforeshow", onBeforeShow);
3029 menu.un("show", onShow);
3031 if(g && menu.events["checkchange"]){
3032 groups[g].remove(menu);
3033 menu.un("checkchange", onCheck);
3038 registerCheckable : function(menuItem){
3039 var g = menuItem.group;
3044 groups[g].push(menuItem);
3045 menuItem.on("beforecheckchange", onBeforeCheck);
3050 unregisterCheckable : function(menuItem){
3051 var g = menuItem.group;
3053 groups[g].remove(menuItem);
3054 menuItem.un("beforecheckchange", onBeforeCheck);
3066 * @class Roo.bootstrap.Menu
3067 * @extends Roo.bootstrap.Component
3068 * Bootstrap Menu class - container for MenuItems
3069 * @cfg {String} type (dropdown|treeview|submenu) type of menu
3070 * @cfg {bool} hidden if the menu should be hidden when rendered.
3071 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
3072 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
3076 * @param {Object} config The config object
3080 Roo.bootstrap.Menu = function(config){
3081 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
3082 if (this.registerMenu && this.type != 'treeview') {
3083 Roo.bootstrap.MenuMgr.register(this);
3090 * Fires before this menu is displayed (return false to block)
3091 * @param {Roo.menu.Menu} this
3096 * Fires before this menu is hidden (return false to block)
3097 * @param {Roo.menu.Menu} this
3102 * Fires after this menu is displayed
3103 * @param {Roo.menu.Menu} this
3108 * Fires after this menu is hidden
3109 * @param {Roo.menu.Menu} this
3114 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
3115 * @param {Roo.menu.Menu} this
3116 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3117 * @param {Roo.EventObject} e
3122 * Fires when the mouse is hovering over this menu
3123 * @param {Roo.menu.Menu} this
3124 * @param {Roo.EventObject} e
3125 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3130 * Fires when the mouse exits this menu
3131 * @param {Roo.menu.Menu} this
3132 * @param {Roo.EventObject} e
3133 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3138 * Fires when a menu item contained in this menu is clicked
3139 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
3140 * @param {Roo.EventObject} e
3144 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
3147 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
3151 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
3154 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
3156 registerMenu : true,
3158 menuItems :false, // stores the menu items..
3168 getChildContainer : function() {
3172 getAutoCreate : function(){
3174 //if (['right'].indexOf(this.align)!==-1) {
3175 // cfg.cn[1].cls += ' pull-right'
3181 cls : 'dropdown-menu' ,
3182 style : 'z-index:1000'
3186 if (this.type === 'submenu') {
3187 cfg.cls = 'submenu active';
3189 if (this.type === 'treeview') {
3190 cfg.cls = 'treeview-menu';
3195 initEvents : function() {
3197 // Roo.log("ADD event");
3198 // Roo.log(this.triggerEl.dom);
3200 this.triggerEl.on('click', this.onTriggerClick, this);
3202 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
3205 if (this.triggerEl.hasClass('nav-item')) {
3206 // dropdown toggle on the 'a' in BS4?
3207 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
3209 this.triggerEl.addClass('dropdown-toggle');
3212 this.el.on('touchstart' , this.onTouch, this);
3214 this.el.on('click' , this.onClick, this);
3216 this.el.on("mouseover", this.onMouseOver, this);
3217 this.el.on("mouseout", this.onMouseOut, this);
3221 findTargetItem : function(e)
3223 var t = e.getTarget(".dropdown-menu-item", this.el, true);
3227 //Roo.log(t); Roo.log(t.id);
3229 //Roo.log(this.menuitems);
3230 return this.menuitems.get(t.id);
3232 //return this.items.get(t.menuItemId);
3238 onTouch : function(e)
3240 Roo.log("menu.onTouch");
3241 //e.stopEvent(); this make the user popdown broken
3245 onClick : function(e)
3247 Roo.log("menu.onClick");
3249 var t = this.findTargetItem(e);
3250 if(!t || t.isContainer){
3255 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
3256 if(t == this.activeItem && t.shouldDeactivate(e)){
3257 this.activeItem.deactivate();
3258 delete this.activeItem;
3262 this.setActiveItem(t, true);
3270 Roo.log('pass click event');
3274 this.fireEvent("click", this, t, e);
3278 if(!t.href.length || t.href == '#'){
3279 (function() { _this.hide(); }).defer(100);
3284 onMouseOver : function(e){
3285 var t = this.findTargetItem(e);
3288 // if(t.canActivate && !t.disabled){
3289 // this.setActiveItem(t, true);
3293 this.fireEvent("mouseover", this, e, t);
3295 isVisible : function(){
3296 return !this.hidden;
3298 onMouseOut : function(e){
3299 var t = this.findTargetItem(e);
3302 // if(t == this.activeItem && t.shouldDeactivate(e)){
3303 // this.activeItem.deactivate();
3304 // delete this.activeItem;
3307 this.fireEvent("mouseout", this, e, t);
3312 * Displays this menu relative to another element
3313 * @param {String/HTMLElement/Roo.Element} element The element to align to
3314 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
3315 * the element (defaults to this.defaultAlign)
3316 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3318 show : function(el, pos, parentMenu)
3320 if (false === this.fireEvent("beforeshow", this)) {
3321 Roo.log("show canceled");
3324 this.parentMenu = parentMenu;
3329 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
3332 * Displays this menu at a specific xy position
3333 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
3334 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3336 showAt : function(xy, parentMenu, /* private: */_e){
3337 this.parentMenu = parentMenu;
3342 this.fireEvent("beforeshow", this);
3343 //xy = this.el.adjustForConstraints(xy);
3347 this.hideMenuItems();
3348 this.hidden = false;
3349 this.triggerEl.addClass('open');
3350 this.el.addClass('show');
3352 // reassign x when hitting right
3353 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
3354 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
3357 // reassign y when hitting bottom
3358 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
3359 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
3362 // but the list may align on trigger left or trigger top... should it be a properity?
3364 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
3369 this.fireEvent("show", this);
3375 this.doFocus.defer(50, this);
3379 doFocus : function(){
3381 this.focusEl.focus();
3386 * Hides this menu and optionally all parent menus
3387 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
3389 hide : function(deep)
3391 if (false === this.fireEvent("beforehide", this)) {
3392 Roo.log("hide canceled");
3395 this.hideMenuItems();
3396 if(this.el && this.isVisible()){
3398 if(this.activeItem){
3399 this.activeItem.deactivate();
3400 this.activeItem = null;
3402 this.triggerEl.removeClass('open');;
3403 this.el.removeClass('show');
3405 this.fireEvent("hide", this);
3407 if(deep === true && this.parentMenu){
3408 this.parentMenu.hide(true);
3412 onTriggerClick : function(e)
3414 Roo.log('trigger click');
3416 var target = e.getTarget();
3418 Roo.log(target.nodeName.toLowerCase());
3420 if(target.nodeName.toLowerCase() === 'i'){
3426 onTriggerPress : function(e)
3428 Roo.log('trigger press');
3429 //Roo.log(e.getTarget());
3430 // Roo.log(this.triggerEl.dom);
3432 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
3433 var pel = Roo.get(e.getTarget());
3434 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
3435 Roo.log('is treeview or dropdown?');
3439 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
3443 if (this.isVisible()) {
3448 this.show(this.triggerEl, '?', false);
3451 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
3458 hideMenuItems : function()
3460 Roo.log("hide Menu Items");
3465 this.el.select('.open',true).each(function(aa) {
3467 aa.removeClass('open');
3471 addxtypeChild : function (tree, cntr) {
3472 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
3474 this.menuitems.add(comp);
3486 this.getEl().dom.innerHTML = '';
3487 this.menuitems.clear();
3501 * @class Roo.bootstrap.MenuItem
3502 * @extends Roo.bootstrap.Component
3503 * Bootstrap MenuItem class
3504 * @cfg {String} html the menu label
3505 * @cfg {String} href the link
3506 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
3507 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
3508 * @cfg {Boolean} active used on sidebars to highlight active itesm
3509 * @cfg {String} fa favicon to show on left of menu item.
3510 * @cfg {Roo.bootsrap.Menu} menu the child menu.
3514 * Create a new MenuItem
3515 * @param {Object} config The config object
3519 Roo.bootstrap.MenuItem = function(config){
3520 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
3525 * The raw click event for the entire grid.
3526 * @param {Roo.bootstrap.MenuItem} this
3527 * @param {Roo.EventObject} e
3533 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
3537 preventDefault: false,
3538 isContainer : false,
3542 getAutoCreate : function(){
3544 if(this.isContainer){
3547 cls: 'dropdown-menu-item '
3557 cls : 'dropdown-item',
3562 if (this.fa !== false) {
3565 cls : 'fa fa-' + this.fa
3574 cls: 'dropdown-menu-item',
3577 if (this.parent().type == 'treeview') {
3578 cfg.cls = 'treeview-menu';
3581 cfg.cls += ' active';
3586 anc.href = this.href || cfg.cn[0].href ;
3587 ctag.html = this.html || cfg.cn[0].html ;
3591 initEvents: function()
3593 if (this.parent().type == 'treeview') {
3594 this.el.select('a').on('click', this.onClick, this);
3598 this.menu.parentType = this.xtype;
3599 this.menu.triggerEl = this.el;
3600 this.menu = this.addxtype(Roo.apply({}, this.menu));
3604 onClick : function(e)
3606 Roo.log('item on click ');
3608 if(this.preventDefault){
3611 //this.parent().hideMenuItems();
3613 this.fireEvent('click', this, e);
3632 * @class Roo.bootstrap.MenuSeparator
3633 * @extends Roo.bootstrap.Component
3634 * Bootstrap MenuSeparator class
3637 * Create a new MenuItem
3638 * @param {Object} config The config object
3642 Roo.bootstrap.MenuSeparator = function(config){
3643 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
3646 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
3648 getAutoCreate : function(){
3667 * @class Roo.bootstrap.Modal
3668 * @extends Roo.bootstrap.Component
3669 * Bootstrap Modal class
3670 * @cfg {String} title Title of dialog
3671 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
3672 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
3673 * @cfg {Boolean} specificTitle default false
3674 * @cfg {Array} buttons Array of buttons or standard button set..
3675 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
3676 * @cfg {Boolean} animate default true
3677 * @cfg {Boolean} allow_close default true
3678 * @cfg {Boolean} fitwindow default false
3679 * @cfg {Number} width fixed width - usefull for chrome extension only really.
3680 * @cfg {Number} height fixed height - usefull for chrome extension only really.
3681 * @cfg {String} size (sm|lg) default empty
3682 * @cfg {Number} max_width set the max width of modal
3686 * Create a new Modal Dialog
3687 * @param {Object} config The config object
3690 Roo.bootstrap.Modal = function(config){
3691 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
3696 * The raw btnclick event for the button
3697 * @param {Roo.EventObject} e
3702 * Fire when dialog resize
3703 * @param {Roo.bootstrap.Modal} this
3704 * @param {Roo.EventObject} e
3708 this.buttons = this.buttons || [];
3711 this.tmpl = Roo.factory(this.tmpl);
3716 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
3718 title : 'test dialog',
3728 specificTitle: false,
3730 buttonPosition: 'right',
3753 onRender : function(ct, position)
3755 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
3758 var cfg = Roo.apply({}, this.getAutoCreate());
3761 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
3763 //if (!cfg.name.length) {
3767 cfg.cls += ' ' + this.cls;
3770 cfg.style = this.style;
3772 this.el = Roo.get(document.body).createChild(cfg, position);
3774 //var type = this.el.dom.type;
3777 if(this.tabIndex !== undefined){
3778 this.el.dom.setAttribute('tabIndex', this.tabIndex);
3781 this.dialogEl = this.el.select('.modal-dialog',true).first();
3782 this.bodyEl = this.el.select('.modal-body',true).first();
3783 this.closeEl = this.el.select('.modal-header .close', true).first();
3784 this.headerEl = this.el.select('.modal-header',true).first();
3785 this.titleEl = this.el.select('.modal-title',true).first();
3786 this.footerEl = this.el.select('.modal-footer',true).first();
3788 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
3790 //this.el.addClass("x-dlg-modal");
3792 if (this.buttons.length) {
3793 Roo.each(this.buttons, function(bb) {
3794 var b = Roo.apply({}, bb);
3795 b.xns = b.xns || Roo.bootstrap;
3796 b.xtype = b.xtype || 'Button';
3797 if (typeof(b.listeners) == 'undefined') {
3798 b.listeners = { click : this.onButtonClick.createDelegate(this) };
3801 var btn = Roo.factory(b);
3803 btn.render(this.getButtonContainer());
3807 // render the children.
3810 if(typeof(this.items) != 'undefined'){
3811 var items = this.items;
3814 for(var i =0;i < items.length;i++) {
3815 nitems.push(this.addxtype(Roo.apply({}, items[i])));
3819 this.items = nitems;
3821 // where are these used - they used to be body/close/footer
3825 //this.el.addClass([this.fieldClass, this.cls]);
3829 getAutoCreate : function()
3831 // we will default to modal-body-overflow - might need to remove or make optional later.
3833 cls : 'modal-body enable-modal-body-overflow ',
3834 html : this.html || ''
3839 cls : 'modal-title',
3843 if(this.specificTitle){
3849 if (this.allow_close && Roo.bootstrap.version == 3) {
3859 if (this.allow_close && Roo.bootstrap.version == 4) {
3869 if(this.size.length){
3870 size = 'modal-' + this.size;
3873 var footer = Roo.bootstrap.version == 3 ?
3875 cls : 'modal-footer',
3879 cls: 'btn-' + this.buttonPosition
3884 { // BS4 uses mr-auto on left buttons....
3885 cls : 'modal-footer'
3896 cls: "modal-dialog " + size,
3899 cls : "modal-content",
3902 cls : 'modal-header',
3917 modal.cls += ' fade';
3923 getChildContainer : function() {
3928 getButtonContainer : function() {
3930 return Roo.bootstrap.version == 4 ?
3931 this.el.select('.modal-footer',true).first()
3932 : this.el.select('.modal-footer div',true).first();
3935 initEvents : function()
3937 if (this.allow_close) {
3938 this.closeEl.on('click', this.hide, this);
3940 Roo.EventManager.onWindowResize(this.resize, this, true);
3948 this.maskEl.setSize(
3949 Roo.lib.Dom.getViewWidth(true),
3950 Roo.lib.Dom.getViewHeight(true)
3953 if (this.fitwindow) {
3957 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
3958 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
3963 if(this.max_width !== 0) {
3965 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
3968 this.setSize(w, this.height);
3972 if(this.max_height) {
3973 this.setSize(w,Math.min(
3975 Roo.lib.Dom.getViewportHeight(true) - 60
3981 if(!this.fit_content) {
3982 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
3986 this.setSize(w, Math.min(
3988 this.headerEl.getHeight() +
3989 this.footerEl.getHeight() +
3990 this.getChildHeight(this.bodyEl.dom.childNodes),
3991 Roo.lib.Dom.getViewportHeight(true) - 60)
3997 setSize : function(w,h)
4008 if (!this.rendered) {
4012 //this.el.setStyle('display', 'block');
4013 this.el.removeClass('hideing');
4014 this.el.dom.style.display='block';
4016 Roo.get(document.body).addClass('modal-open');
4018 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
4021 this.el.addClass('show');
4022 this.el.addClass('in');
4025 this.el.addClass('show');
4026 this.el.addClass('in');
4029 // not sure how we can show data in here..
4031 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
4034 Roo.get(document.body).addClass("x-body-masked");
4036 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
4037 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4038 this.maskEl.dom.style.display = 'block';
4039 this.maskEl.addClass('show');
4044 this.fireEvent('show', this);
4046 // set zindex here - otherwise it appears to be ignored...
4047 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4050 this.items.forEach( function(e) {
4051 e.layout ? e.layout() : false;
4059 if(this.fireEvent("beforehide", this) !== false){
4061 this.maskEl.removeClass('show');
4063 this.maskEl.dom.style.display = '';
4064 Roo.get(document.body).removeClass("x-body-masked");
4065 this.el.removeClass('in');
4066 this.el.select('.modal-dialog', true).first().setStyle('transform','');
4068 if(this.animate){ // why
4069 this.el.addClass('hideing');
4070 this.el.removeClass('show');
4072 if (!this.el.hasClass('hideing')) {
4073 return; // it's been shown again...
4076 this.el.dom.style.display='';
4078 Roo.get(document.body).removeClass('modal-open');
4079 this.el.removeClass('hideing');
4083 this.el.removeClass('show');
4084 this.el.dom.style.display='';
4085 Roo.get(document.body).removeClass('modal-open');
4088 this.fireEvent('hide', this);
4091 isVisible : function()
4094 return this.el.hasClass('show') && !this.el.hasClass('hideing');
4098 addButton : function(str, cb)
4102 var b = Roo.apply({}, { html : str } );
4103 b.xns = b.xns || Roo.bootstrap;
4104 b.xtype = b.xtype || 'Button';
4105 if (typeof(b.listeners) == 'undefined') {
4106 b.listeners = { click : cb.createDelegate(this) };
4109 var btn = Roo.factory(b);
4111 btn.render(this.getButtonContainer());
4117 setDefaultButton : function(btn)
4119 //this.el.select('.modal-footer').()
4122 resizeTo: function(w,h)
4124 this.dialogEl.setWidth(w);
4126 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
4128 this.bodyEl.setHeight(h - diff);
4130 this.fireEvent('resize', this);
4133 setContentSize : function(w, h)
4137 onButtonClick: function(btn,e)
4140 this.fireEvent('btnclick', btn.name, e);
4143 * Set the title of the Dialog
4144 * @param {String} str new Title
4146 setTitle: function(str) {
4147 this.titleEl.dom.innerHTML = str;
4150 * Set the body of the Dialog
4151 * @param {String} str new Title
4153 setBody: function(str) {
4154 this.bodyEl.dom.innerHTML = str;
4157 * Set the body of the Dialog using the template
4158 * @param {Obj} data - apply this data to the template and replace the body contents.
4160 applyBody: function(obj)
4163 Roo.log("Error - using apply Body without a template");
4166 this.tmpl.overwrite(this.bodyEl, obj);
4169 getChildHeight : function(child_nodes)
4173 child_nodes.length == 0
4178 var child_height = 0;
4180 for(var i = 0; i < child_nodes.length; i++) {
4183 * for modal with tabs...
4184 if(child_nodes[i].classList.contains('roo-layout-panel')) {
4186 var layout_childs = child_nodes[i].childNodes;
4188 for(var j = 0; j < layout_childs.length; j++) {
4190 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
4192 var layout_body_childs = layout_childs[j].childNodes;
4194 for(var k = 0; k < layout_body_childs.length; k++) {
4196 if(layout_body_childs[k].classList.contains('navbar')) {
4197 child_height += layout_body_childs[k].offsetHeight;
4201 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
4203 var layout_body_tab_childs = layout_body_childs[k].childNodes;
4205 for(var m = 0; m < layout_body_tab_childs.length; m++) {
4207 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
4208 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
4223 child_height += child_nodes[i].offsetHeight;
4224 // Roo.log(child_nodes[i].offsetHeight);
4227 return child_height;
4233 Roo.apply(Roo.bootstrap.Modal, {
4235 * Button config that displays a single OK button
4244 * Button config that displays Yes and No buttons
4260 * Button config that displays OK and Cancel buttons
4275 * Button config that displays Yes, No and Cancel buttons
4299 * messagebox - can be used as a replace
4303 * @class Roo.MessageBox
4304 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
4308 Roo.Msg.alert('Status', 'Changes saved successfully.');
4310 // Prompt for user data:
4311 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
4313 // process text value...
4317 // Show a dialog using config options:
4319 title:'Save Changes?',
4320 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
4321 buttons: Roo.Msg.YESNOCANCEL,
4328 Roo.bootstrap.MessageBox = function(){
4329 var dlg, opt, mask, waitTimer;
4330 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
4331 var buttons, activeTextEl, bwidth;
4335 var handleButton = function(button){
4337 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
4341 var handleHide = function(){
4343 dlg.el.removeClass(opt.cls);
4346 // Roo.TaskMgr.stop(waitTimer);
4347 // waitTimer = null;
4352 var updateButtons = function(b){
4355 buttons["ok"].hide();
4356 buttons["cancel"].hide();
4357 buttons["yes"].hide();
4358 buttons["no"].hide();
4359 dlg.footerEl.hide();
4363 dlg.footerEl.show();
4364 for(var k in buttons){
4365 if(typeof buttons[k] != "function"){
4368 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
4369 width += buttons[k].el.getWidth()+15;
4379 var handleEsc = function(d, k, e){
4380 if(opt && opt.closable !== false){
4390 * Returns a reference to the underlying {@link Roo.BasicDialog} element
4391 * @return {Roo.BasicDialog} The BasicDialog element
4393 getDialog : function(){
4395 dlg = new Roo.bootstrap.Modal( {
4398 //constraintoviewport:false,
4400 //collapsible : false,
4405 //buttonAlign:"center",
4406 closeClick : function(){
4407 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
4410 handleButton("cancel");
4415 dlg.on("hide", handleHide);
4417 //dlg.addKeyListener(27, handleEsc);
4419 this.buttons = buttons;
4420 var bt = this.buttonText;
4421 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
4422 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
4423 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
4424 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
4426 bodyEl = dlg.bodyEl.createChild({
4428 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
4429 '<textarea class="roo-mb-textarea"></textarea>' +
4430 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
4432 msgEl = bodyEl.dom.firstChild;
4433 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
4434 textboxEl.enableDisplayMode();
4435 textboxEl.addKeyListener([10,13], function(){
4436 if(dlg.isVisible() && opt && opt.buttons){
4439 }else if(opt.buttons.yes){
4440 handleButton("yes");
4444 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
4445 textareaEl.enableDisplayMode();
4446 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
4447 progressEl.enableDisplayMode();
4449 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
4450 var pf = progressEl.dom.firstChild;
4452 pp = Roo.get(pf.firstChild);
4453 pp.setHeight(pf.offsetHeight);
4461 * Updates the message box body text
4462 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
4463 * the XHTML-compliant non-breaking space character '&#160;')
4464 * @return {Roo.MessageBox} This message box
4466 updateText : function(text)
4468 if(!dlg.isVisible() && !opt.width){
4469 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
4470 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
4472 msgEl.innerHTML = text || ' ';
4474 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
4475 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
4477 Math.min(opt.width || cw , this.maxWidth),
4478 Math.max(opt.minWidth || this.minWidth, bwidth)
4481 activeTextEl.setWidth(w);
4483 if(dlg.isVisible()){
4484 dlg.fixedcenter = false;
4486 // to big, make it scroll. = But as usual stupid IE does not support
4489 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
4490 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
4491 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
4493 bodyEl.dom.style.height = '';
4494 bodyEl.dom.style.overflowY = '';
4497 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
4499 bodyEl.dom.style.overflowX = '';
4502 dlg.setContentSize(w, bodyEl.getHeight());
4503 if(dlg.isVisible()){
4504 dlg.fixedcenter = true;
4510 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
4511 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
4512 * @param {Number} value Any number between 0 and 1 (e.g., .5)
4513 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
4514 * @return {Roo.MessageBox} This message box
4516 updateProgress : function(value, text){
4518 this.updateText(text);
4521 if (pp) { // weird bug on my firefox - for some reason this is not defined
4522 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
4523 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
4529 * Returns true if the message box is currently displayed
4530 * @return {Boolean} True if the message box is visible, else false
4532 isVisible : function(){
4533 return dlg && dlg.isVisible();
4537 * Hides the message box if it is displayed
4540 if(this.isVisible()){
4546 * Displays a new message box, or reinitializes an existing message box, based on the config options
4547 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
4548 * The following config object properties are supported:
4550 Property Type Description
4551 ---------- --------------- ------------------------------------------------------------------------------------
4552 animEl String/Element An id or Element from which the message box should animate as it opens and
4553 closes (defaults to undefined)
4554 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
4555 cancel:'Bar'}), or false to not show any buttons (defaults to false)
4556 closable Boolean False to hide the top-right close button (defaults to true). Note that
4557 progress and wait dialogs will ignore this property and always hide the
4558 close button as they can only be closed programmatically.
4559 cls String A custom CSS class to apply to the message box element
4560 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
4561 displayed (defaults to 75)
4562 fn Function A callback function to execute after closing the dialog. The arguments to the
4563 function will be btn (the name of the button that was clicked, if applicable,
4564 e.g. "ok"), and text (the value of the active text field, if applicable).
4565 Progress and wait dialogs will ignore this option since they do not respond to
4566 user actions and can only be closed programmatically, so any required function
4567 should be called by the same code after it closes the dialog.
4568 icon String A CSS class that provides a background image to be used as an icon for
4569 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
4570 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
4571 minWidth Number The minimum width in pixels of the message box (defaults to 100)
4572 modal Boolean False to allow user interaction with the page while the message box is
4573 displayed (defaults to true)
4574 msg String A string that will replace the existing message box body text (defaults
4575 to the XHTML-compliant non-breaking space character ' ')
4576 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
4577 progress Boolean True to display a progress bar (defaults to false)
4578 progressText String The text to display inside the progress bar if progress = true (defaults to '')
4579 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
4580 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
4581 title String The title text
4582 value String The string value to set into the active textbox element if displayed
4583 wait Boolean True to display a progress bar (defaults to false)
4584 width Number The width of the dialog in pixels
4591 msg: 'Please enter your address:',
4593 buttons: Roo.MessageBox.OKCANCEL,
4596 animEl: 'addAddressBtn'
4599 * @param {Object} config Configuration options
4600 * @return {Roo.MessageBox} This message box
4602 show : function(options)
4605 // this causes nightmares if you show one dialog after another
4606 // especially on callbacks..
4608 if(this.isVisible()){
4611 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
4612 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
4613 Roo.log("New Dialog Message:" + options.msg )
4614 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
4615 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
4618 var d = this.getDialog();
4620 d.setTitle(opt.title || " ");
4621 d.closeEl.setDisplayed(opt.closable !== false);
4622 activeTextEl = textboxEl;
4623 opt.prompt = opt.prompt || (opt.multiline ? true : false);
4628 textareaEl.setHeight(typeof opt.multiline == "number" ?
4629 opt.multiline : this.defaultTextHeight);
4630 activeTextEl = textareaEl;
4639 progressEl.setDisplayed(opt.progress === true);
4641 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
4643 this.updateProgress(0);
4644 activeTextEl.dom.value = opt.value || "";
4646 dlg.setDefaultButton(activeTextEl);
4648 var bs = opt.buttons;
4652 }else if(bs && bs.yes){
4653 db = buttons["yes"];
4655 dlg.setDefaultButton(db);
4657 bwidth = updateButtons(opt.buttons);
4658 this.updateText(opt.msg);
4660 d.el.addClass(opt.cls);
4662 d.proxyDrag = opt.proxyDrag === true;
4663 d.modal = opt.modal !== false;
4664 d.mask = opt.modal !== false ? mask : false;
4666 // force it to the end of the z-index stack so it gets a cursor in FF
4667 document.body.appendChild(dlg.el.dom);
4668 d.animateTarget = null;
4669 d.show(options.animEl);
4675 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
4676 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
4677 * and closing the message box when the process is complete.
4678 * @param {String} title The title bar text
4679 * @param {String} msg The message box body text
4680 * @return {Roo.MessageBox} This message box
4682 progress : function(title, msg){
4689 minWidth: this.minProgressWidth,
4696 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
4697 * If a callback function is passed it will be called after the user clicks the button, and the
4698 * id of the button that was clicked will be passed as the only parameter to the callback
4699 * (could also be the top-right close button).
4700 * @param {String} title The title bar text
4701 * @param {String} msg The message box body text
4702 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4703 * @param {Object} scope (optional) The scope of the callback function
4704 * @return {Roo.MessageBox} This message box
4706 alert : function(title, msg, fn, scope)
4721 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
4722 * interaction while waiting for a long-running process to complete that does not have defined intervals.
4723 * You are responsible for closing the message box when the process is complete.
4724 * @param {String} msg The message box body text
4725 * @param {String} title (optional) The title bar text
4726 * @return {Roo.MessageBox} This message box
4728 wait : function(msg, title){
4739 waitTimer = Roo.TaskMgr.start({
4741 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
4749 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
4750 * If a callback function is passed it will be called after the user clicks either button, and the id of the
4751 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
4752 * @param {String} title The title bar text
4753 * @param {String} msg The message box body text
4754 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4755 * @param {Object} scope (optional) The scope of the callback function
4756 * @return {Roo.MessageBox} This message box
4758 confirm : function(title, msg, fn, scope){
4762 buttons: this.YESNO,
4771 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
4772 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
4773 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
4774 * (could also be the top-right close button) and the text that was entered will be passed as the two
4775 * parameters to the callback.
4776 * @param {String} title The title bar text
4777 * @param {String} msg The message box body text
4778 * @param {Function} fn (optional) The callback function invoked after the message box is closed
4779 * @param {Object} scope (optional) The scope of the callback function
4780 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
4781 * property, or the height in pixels to create the textbox (defaults to false / single-line)
4782 * @return {Roo.MessageBox} This message box
4784 prompt : function(title, msg, fn, scope, multiline){
4788 buttons: this.OKCANCEL,
4793 multiline: multiline,
4800 * Button config that displays a single OK button
4805 * Button config that displays Yes and No buttons
4808 YESNO : {yes:true, no:true},
4810 * Button config that displays OK and Cancel buttons
4813 OKCANCEL : {ok:true, cancel:true},
4815 * Button config that displays Yes, No and Cancel buttons
4818 YESNOCANCEL : {yes:true, no:true, cancel:true},
4821 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
4824 defaultTextHeight : 75,
4826 * The maximum width in pixels of the message box (defaults to 600)
4831 * The minimum width in pixels of the message box (defaults to 100)
4836 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
4837 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
4840 minProgressWidth : 250,
4842 * An object containing the default button text strings that can be overriden for localized language support.
4843 * Supported properties are: ok, cancel, yes and no.
4844 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
4857 * Shorthand for {@link Roo.MessageBox}
4859 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
4860 Roo.Msg = Roo.Msg || Roo.MessageBox;
4869 * @class Roo.bootstrap.Navbar
4870 * @extends Roo.bootstrap.Component
4871 * Bootstrap Navbar class
4874 * Create a new Navbar
4875 * @param {Object} config The config object
4879 Roo.bootstrap.Navbar = function(config){
4880 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
4884 * @event beforetoggle
4885 * Fire before toggle the menu
4886 * @param {Roo.EventObject} e
4888 "beforetoggle" : true
4892 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
4901 getAutoCreate : function(){
4904 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
4908 initEvents :function ()
4910 //Roo.log(this.el.select('.navbar-toggle',true));
4911 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
4918 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
4920 var size = this.el.getSize();
4921 this.maskEl.setSize(size.width, size.height);
4922 this.maskEl.enableDisplayMode("block");
4931 getChildContainer : function()
4933 if (this.el && this.el.select('.collapse').getCount()) {
4934 return this.el.select('.collapse',true).first();
4949 onToggle : function()
4952 if(this.fireEvent('beforetoggle', this) === false){
4955 var ce = this.el.select('.navbar-collapse',true).first();
4957 if (!ce.hasClass('show')) {
4967 * Expand the navbar pulldown
4969 expand : function ()
4972 var ce = this.el.select('.navbar-collapse',true).first();
4973 if (ce.hasClass('collapsing')) {
4976 ce.dom.style.height = '';
4978 ce.addClass('in'); // old...
4979 ce.removeClass('collapse');
4980 ce.addClass('show');
4981 var h = ce.getHeight();
4983 ce.removeClass('show');
4984 // at this point we should be able to see it..
4985 ce.addClass('collapsing');
4987 ce.setHeight(0); // resize it ...
4988 ce.on('transitionend', function() {
4989 //Roo.log('done transition');
4990 ce.removeClass('collapsing');
4991 ce.addClass('show');
4992 ce.removeClass('collapse');
4994 ce.dom.style.height = '';
4995 }, this, { single: true} );
4997 ce.dom.scrollTop = 0;
5000 * Collapse the navbar pulldown
5002 collapse : function()
5004 var ce = this.el.select('.navbar-collapse',true).first();
5006 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
5007 // it's collapsed or collapsing..
5010 ce.removeClass('in'); // old...
5011 ce.setHeight(ce.getHeight());
5012 ce.removeClass('show');
5013 ce.addClass('collapsing');
5015 ce.on('transitionend', function() {
5016 ce.dom.style.height = '';
5017 ce.removeClass('collapsing');
5018 ce.addClass('collapse');
5019 }, this, { single: true} );
5039 * @class Roo.bootstrap.NavSimplebar
5040 * @extends Roo.bootstrap.Navbar
5041 * Bootstrap Sidebar class
5043 * @cfg {Boolean} inverse is inverted color
5045 * @cfg {String} type (nav | pills | tabs)
5046 * @cfg {Boolean} arrangement stacked | justified
5047 * @cfg {String} align (left | right) alignment
5049 * @cfg {Boolean} main (true|false) main nav bar? default false
5050 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
5052 * @cfg {String} tag (header|footer|nav|div) default is nav
5054 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
5058 * Create a new Sidebar
5059 * @param {Object} config The config object
5063 Roo.bootstrap.NavSimplebar = function(config){
5064 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
5067 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
5083 getAutoCreate : function(){
5087 tag : this.tag || 'div',
5088 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
5090 if (['light','white'].indexOf(this.weight) > -1) {
5091 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5093 cfg.cls += ' bg-' + this.weight;
5096 cfg.cls += ' navbar-inverse';
5100 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
5102 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
5111 cls: 'nav nav-' + this.xtype,
5117 this.type = this.type || 'nav';
5118 if (['tabs','pills'].indexOf(this.type) != -1) {
5119 cfg.cn[0].cls += ' nav-' + this.type
5123 if (this.type!=='nav') {
5124 Roo.log('nav type must be nav/tabs/pills')
5126 cfg.cn[0].cls += ' navbar-nav'
5132 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
5133 cfg.cn[0].cls += ' nav-' + this.arrangement;
5137 if (this.align === 'right') {
5138 cfg.cn[0].cls += ' navbar-right';
5163 * navbar-expand-md fixed-top
5167 * @class Roo.bootstrap.NavHeaderbar
5168 * @extends Roo.bootstrap.NavSimplebar
5169 * Bootstrap Sidebar class
5171 * @cfg {String} brand what is brand
5172 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
5173 * @cfg {String} brand_href href of the brand
5174 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
5175 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
5176 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
5177 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
5180 * Create a new Sidebar
5181 * @param {Object} config The config object
5185 Roo.bootstrap.NavHeaderbar = function(config){
5186 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
5190 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
5197 desktopCenter : false,
5200 getAutoCreate : function(){
5203 tag: this.nav || 'nav',
5204 cls: 'navbar navbar-expand-md',
5210 if (this.desktopCenter) {
5211 cn.push({cls : 'container', cn : []});
5219 cls: 'navbar-toggle navbar-toggler',
5220 'data-toggle': 'collapse',
5225 html: 'Toggle navigation'
5229 cls: 'icon-bar navbar-toggler-icon'
5242 cn.push( Roo.bootstrap.version == 4 ? btn : {
5244 cls: 'navbar-header',
5253 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse collapse navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
5257 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
5259 if (['light','white'].indexOf(this.weight) > -1) {
5260 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5262 cfg.cls += ' bg-' + this.weight;
5265 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
5266 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
5268 // tag can override this..
5270 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
5273 if (this.brand !== '') {
5274 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
5275 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
5277 href: this.brand_href ? this.brand_href : '#',
5278 cls: 'navbar-brand',
5286 cfg.cls += ' main-nav';
5294 getHeaderChildContainer : function()
5296 if (this.srButton && this.el.select('.navbar-header').getCount()) {
5297 return this.el.select('.navbar-header',true).first();
5300 return this.getChildContainer();
5303 getChildContainer : function()
5306 return this.el.select('.roo-navbar-collapse',true).first();
5311 initEvents : function()
5313 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
5315 if (this.autohide) {
5320 Roo.get(document).on('scroll',function(e) {
5321 var ns = Roo.get(document).getScroll().top;
5322 var os = prevScroll;
5326 ft.removeClass('slideDown');
5327 ft.addClass('slideUp');
5330 ft.removeClass('slideUp');
5331 ft.addClass('slideDown');
5352 * @class Roo.bootstrap.NavSidebar
5353 * @extends Roo.bootstrap.Navbar
5354 * Bootstrap Sidebar class
5357 * Create a new Sidebar
5358 * @param {Object} config The config object
5362 Roo.bootstrap.NavSidebar = function(config){
5363 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
5366 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
5368 sidebar : true, // used by Navbar Item and NavbarGroup at present...
5370 getAutoCreate : function(){
5375 cls: 'sidebar sidebar-nav'
5397 * @class Roo.bootstrap.NavGroup
5398 * @extends Roo.bootstrap.Component
5399 * Bootstrap NavGroup class
5400 * @cfg {String} align (left|right)
5401 * @cfg {Boolean} inverse
5402 * @cfg {String} type (nav|pills|tab) default nav
5403 * @cfg {String} navId - reference Id for navbar.
5407 * Create a new nav group
5408 * @param {Object} config The config object
5411 Roo.bootstrap.NavGroup = function(config){
5412 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
5415 Roo.bootstrap.NavGroup.register(this);
5419 * Fires when the active item changes
5420 * @param {Roo.bootstrap.NavGroup} this
5421 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
5422 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
5429 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
5440 getAutoCreate : function()
5442 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
5448 if (Roo.bootstrap.version == 4) {
5449 if (['tabs','pills'].indexOf(this.type) != -1) {
5450 cfg.cls += ' nav-' + this.type;
5452 // trying to remove so header bar can right align top?
5453 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
5454 // do not use on header bar...
5455 cfg.cls += ' navbar-nav';
5460 if (['tabs','pills'].indexOf(this.type) != -1) {
5461 cfg.cls += ' nav-' + this.type
5463 if (this.type !== 'nav') {
5464 Roo.log('nav type must be nav/tabs/pills')
5466 cfg.cls += ' navbar-nav'
5470 if (this.parent() && this.parent().sidebar) {
5473 cls: 'dashboard-menu sidebar-menu'
5479 if (this.form === true) {
5482 cls: 'navbar-form form-inline'
5484 //nav navbar-right ml-md-auto
5485 if (this.align === 'right') {
5486 cfg.cls += ' navbar-right ml-md-auto';
5488 cfg.cls += ' navbar-left';
5492 if (this.align === 'right') {
5493 cfg.cls += ' navbar-right ml-md-auto';
5495 cfg.cls += ' mr-auto';
5499 cfg.cls += ' navbar-inverse';
5507 * sets the active Navigation item
5508 * @param {Roo.bootstrap.NavItem} the new current navitem
5510 setActiveItem : function(item)
5513 Roo.each(this.navItems, function(v){
5518 v.setActive(false, true);
5525 item.setActive(true, true);
5526 this.fireEvent('changed', this, item, prev);
5531 * gets the active Navigation item
5532 * @return {Roo.bootstrap.NavItem} the current navitem
5534 getActive : function()
5538 Roo.each(this.navItems, function(v){
5549 indexOfNav : function()
5553 Roo.each(this.navItems, function(v,i){
5564 * adds a Navigation item
5565 * @param {Roo.bootstrap.NavItem} the navitem to add
5567 addItem : function(cfg)
5569 if (this.form && Roo.bootstrap.version == 4) {
5572 var cn = new Roo.bootstrap.NavItem(cfg);
5574 cn.parentId = this.id;
5575 cn.onRender(this.el, null);
5579 * register a Navigation item
5580 * @param {Roo.bootstrap.NavItem} the navitem to add
5582 register : function(item)
5584 this.navItems.push( item);
5585 item.navId = this.navId;
5590 * clear all the Navigation item
5593 clearAll : function()
5596 this.el.dom.innerHTML = '';
5599 getNavItem: function(tabId)
5602 Roo.each(this.navItems, function(e) {
5603 if (e.tabId == tabId) {
5613 setActiveNext : function()
5615 var i = this.indexOfNav(this.getActive());
5616 if (i > this.navItems.length) {
5619 this.setActiveItem(this.navItems[i+1]);
5621 setActivePrev : function()
5623 var i = this.indexOfNav(this.getActive());
5627 this.setActiveItem(this.navItems[i-1]);
5629 clearWasActive : function(except) {
5630 Roo.each(this.navItems, function(e) {
5631 if (e.tabId != except.tabId && e.was_active) {
5632 e.was_active = false;
5639 getWasActive : function ()
5642 Roo.each(this.navItems, function(e) {
5657 Roo.apply(Roo.bootstrap.NavGroup, {
5661 * register a Navigation Group
5662 * @param {Roo.bootstrap.NavGroup} the navgroup to add
5664 register : function(navgrp)
5666 this.groups[navgrp.navId] = navgrp;
5670 * fetch a Navigation Group based on the navigation ID
5671 * @param {string} the navgroup to add
5672 * @returns {Roo.bootstrap.NavGroup} the navgroup
5674 get: function(navId) {
5675 if (typeof(this.groups[navId]) == 'undefined') {
5677 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
5679 return this.groups[navId] ;
5694 * @class Roo.bootstrap.NavItem
5695 * @extends Roo.bootstrap.Component
5696 * Bootstrap Navbar.NavItem class
5697 * @cfg {String} href link to
5698 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
5700 * @cfg {String} html content of button
5701 * @cfg {String} badge text inside badge
5702 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
5703 * @cfg {String} glyphicon DEPRICATED - use fa
5704 * @cfg {String} icon DEPRICATED - use fa
5705 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
5706 * @cfg {Boolean} active Is item active
5707 * @cfg {Boolean} disabled Is item disabled
5709 * @cfg {Boolean} preventDefault (true | false) default false
5710 * @cfg {String} tabId the tab that this item activates.
5711 * @cfg {String} tagtype (a|span) render as a href or span?
5712 * @cfg {Boolean} animateRef (true|false) link to element default false
5715 * Create a new Navbar Item
5716 * @param {Object} config The config object
5718 Roo.bootstrap.NavItem = function(config){
5719 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
5724 * The raw click event for the entire grid.
5725 * @param {Roo.EventObject} e
5730 * Fires when the active item active state changes
5731 * @param {Roo.bootstrap.NavItem} this
5732 * @param {boolean} state the new state
5738 * Fires when scroll to element
5739 * @param {Roo.bootstrap.NavItem} this
5740 * @param {Object} options
5741 * @param {Roo.EventObject} e
5749 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
5758 preventDefault : false,
5766 button_outline : false,
5770 getAutoCreate : function(){
5778 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
5780 if (this.disabled) {
5781 cfg.cls += ' disabled';
5785 if (this.button_weight.length) {
5786 cfg.tag = this.href ? 'a' : 'button';
5787 cfg.html = this.html || '';
5788 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
5790 cfg.href = this.href;
5793 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
5796 // menu .. should add dropdown-menu class - so no need for carat..
5798 if (this.badge !== '') {
5800 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
5805 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
5809 href : this.href || "#",
5810 html: this.html || ''
5813 if (this.tagtype == 'a') {
5814 cfg.cn[0].cls = 'nav-link';
5817 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
5820 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
5822 if(this.glyphicon) {
5823 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
5828 cfg.cn[0].html += " <span class='caret'></span>";
5832 if (this.badge !== '') {
5834 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
5842 onRender : function(ct, position)
5844 // Roo.log("Call onRender: " + this.xtype);
5845 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
5849 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
5850 this.navLink = this.el.select('.nav-link',true).first();
5855 initEvents: function()
5857 if (typeof (this.menu) != 'undefined') {
5858 this.menu.parentType = this.xtype;
5859 this.menu.triggerEl = this.el;
5860 this.menu = this.addxtype(Roo.apply({}, this.menu));
5863 this.el.select('a',true).on('click', this.onClick, this);
5865 if(this.tagtype == 'span'){
5866 this.el.select('span',true).on('click', this.onClick, this);
5869 // at this point parent should be available..
5870 this.parent().register(this);
5873 onClick : function(e)
5875 if (e.getTarget('.dropdown-menu-item')) {
5876 // did you click on a menu itemm.... - then don't trigger onclick..
5881 this.preventDefault ||
5884 Roo.log("NavItem - prevent Default?");
5888 if (this.disabled) {
5892 var tg = Roo.bootstrap.TabGroup.get(this.navId);
5893 if (tg && tg.transition) {
5894 Roo.log("waiting for the transitionend");
5900 //Roo.log("fire event clicked");
5901 if(this.fireEvent('click', this, e) === false){
5905 if(this.tagtype == 'span'){
5909 //Roo.log(this.href);
5910 var ael = this.el.select('a',true).first();
5913 if(ael && this.animateRef && this.href.indexOf('#') > -1){
5914 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
5915 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
5916 return; // ignore... - it's a 'hash' to another page.
5918 Roo.log("NavItem - prevent Default?");
5920 this.scrollToElement(e);
5924 var p = this.parent();
5926 if (['tabs','pills'].indexOf(p.type)!==-1) {
5927 if (typeof(p.setActiveItem) !== 'undefined') {
5928 p.setActiveItem(this);
5932 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
5933 if (p.parentType == 'NavHeaderbar' && !this.menu) {
5934 // remove the collapsed menu expand...
5935 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
5939 isActive: function () {
5942 setActive : function(state, fire, is_was_active)
5944 if (this.active && !state && this.navId) {
5945 this.was_active = true;
5946 var nv = Roo.bootstrap.NavGroup.get(this.navId);
5948 nv.clearWasActive(this);
5952 this.active = state;
5955 this.el.removeClass('active');
5956 this.navLink ? this.navLink.removeClass('active') : false;
5957 } else if (!this.el.hasClass('active')) {
5959 this.el.addClass('active');
5960 if (Roo.bootstrap.version == 4 && this.navLink ) {
5961 this.navLink.addClass('active');
5966 this.fireEvent('changed', this, state);
5969 // show a panel if it's registered and related..
5971 if (!this.navId || !this.tabId || !state || is_was_active) {
5975 var tg = Roo.bootstrap.TabGroup.get(this.navId);
5979 var pan = tg.getPanelByName(this.tabId);
5983 // if we can not flip to new panel - go back to old nav highlight..
5984 if (false == tg.showPanel(pan)) {
5985 var nv = Roo.bootstrap.NavGroup.get(this.navId);
5987 var onav = nv.getWasActive();
5989 onav.setActive(true, false, true);
5998 // this should not be here...
5999 setDisabled : function(state)
6001 this.disabled = state;
6003 this.el.removeClass('disabled');
6004 } else if (!this.el.hasClass('disabled')) {
6005 this.el.addClass('disabled');
6011 * Fetch the element to display the tooltip on.
6012 * @return {Roo.Element} defaults to this.el
6014 tooltipEl : function()
6016 return this.el.select('' + this.tagtype + '', true).first();
6019 scrollToElement : function(e)
6021 var c = document.body;
6024 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
6026 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
6027 c = document.documentElement;
6030 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
6036 var o = target.calcOffsetsTo(c);
6043 this.fireEvent('scrollto', this, options, e);
6045 Roo.get(c).scrollTo('top', options.value, true);
6058 * <span> icon </span>
6059 * <span> text </span>
6060 * <span>badge </span>
6064 * @class Roo.bootstrap.NavSidebarItem
6065 * @extends Roo.bootstrap.NavItem
6066 * Bootstrap Navbar.NavSidebarItem class
6067 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
6068 * {Boolean} open is the menu open
6069 * {Boolean} buttonView use button as the tigger el rather that a (default false)
6070 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
6071 * {String} buttonSize (sm|md|lg)the extra classes for the button
6072 * {Boolean} showArrow show arrow next to the text (default true)
6074 * Create a new Navbar Button
6075 * @param {Object} config The config object
6077 Roo.bootstrap.NavSidebarItem = function(config){
6078 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
6083 * The raw click event for the entire grid.
6084 * @param {Roo.EventObject} e
6089 * Fires when the active item active state changes
6090 * @param {Roo.bootstrap.NavSidebarItem} this
6091 * @param {boolean} state the new state
6099 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
6101 badgeWeight : 'default',
6107 buttonWeight : 'default',
6113 getAutoCreate : function(){
6118 href : this.href || '#',
6124 if(this.buttonView){
6127 href : this.href || '#',
6128 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
6141 cfg.cls += ' active';
6144 if (this.disabled) {
6145 cfg.cls += ' disabled';
6148 cfg.cls += ' open x-open';
6151 if (this.glyphicon || this.icon) {
6152 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
6153 a.cn.push({ tag : 'i', cls : c }) ;
6156 if(!this.buttonView){
6159 html : this.html || ''
6166 if (this.badge !== '') {
6167 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
6173 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
6176 a.cls += ' dropdown-toggle treeview' ;
6182 initEvents : function()
6184 if (typeof (this.menu) != 'undefined') {
6185 this.menu.parentType = this.xtype;
6186 this.menu.triggerEl = this.el;
6187 this.menu = this.addxtype(Roo.apply({}, this.menu));
6190 this.el.on('click', this.onClick, this);
6192 if(this.badge !== ''){
6193 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
6198 onClick : function(e)
6205 if(this.preventDefault){
6209 this.fireEvent('click', this, e);
6212 disable : function()
6214 this.setDisabled(true);
6219 this.setDisabled(false);
6222 setDisabled : function(state)
6224 if(this.disabled == state){
6228 this.disabled = state;
6231 this.el.addClass('disabled');
6235 this.el.removeClass('disabled');
6240 setActive : function(state)
6242 if(this.active == state){
6246 this.active = state;
6249 this.el.addClass('active');
6253 this.el.removeClass('active');
6258 isActive: function ()
6263 setBadge : function(str)
6269 this.badgeEl.dom.innerHTML = str;
6286 * @class Roo.bootstrap.Row
6287 * @extends Roo.bootstrap.Component
6288 * Bootstrap Row class (contains columns...)
6292 * @param {Object} config The config object
6295 Roo.bootstrap.Row = function(config){
6296 Roo.bootstrap.Row.superclass.constructor.call(this, config);
6299 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
6301 getAutoCreate : function(){
6320 * @class Roo.bootstrap.Pagination
6321 * @extends Roo.bootstrap.Component
6322 * Bootstrap Pagination class
6323 * @cfg {String} size xs | sm | md | lg
6324 * @cfg {Boolean} inverse false | true
6327 * Create a new Pagination
6328 * @param {Object} config The config object
6331 Roo.bootstrap.Pagination = function(config){
6332 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
6335 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
6341 getAutoCreate : function(){
6347 cfg.cls += ' inverse';
6353 cfg.cls += " " + this.cls;
6371 * @class Roo.bootstrap.PaginationItem
6372 * @extends Roo.bootstrap.Component
6373 * Bootstrap PaginationItem class
6374 * @cfg {String} html text
6375 * @cfg {String} href the link
6376 * @cfg {Boolean} preventDefault (true | false) default true
6377 * @cfg {Boolean} active (true | false) default false
6378 * @cfg {Boolean} disabled default false
6382 * Create a new PaginationItem
6383 * @param {Object} config The config object
6387 Roo.bootstrap.PaginationItem = function(config){
6388 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
6393 * The raw click event for the entire grid.
6394 * @param {Roo.EventObject} e
6400 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
6404 preventDefault: true,
6409 getAutoCreate : function(){
6415 href : this.href ? this.href : '#',
6416 html : this.html ? this.html : ''
6426 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
6430 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
6436 initEvents: function() {
6438 this.el.on('click', this.onClick, this);
6441 onClick : function(e)
6443 Roo.log('PaginationItem on click ');
6444 if(this.preventDefault){
6452 this.fireEvent('click', this, e);
6468 * @class Roo.bootstrap.Slider
6469 * @extends Roo.bootstrap.Component
6470 * Bootstrap Slider class
6473 * Create a new Slider
6474 * @param {Object} config The config object
6477 Roo.bootstrap.Slider = function(config){
6478 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
6481 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
6483 getAutoCreate : function(){
6487 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
6491 cls: 'ui-slider-handle ui-state-default ui-corner-all'
6503 * Ext JS Library 1.1.1
6504 * Copyright(c) 2006-2007, Ext JS, LLC.
6506 * Originally Released Under LGPL - original licence link has changed is not relivant.
6509 * <script type="text/javascript">
6514 * @class Roo.grid.ColumnModel
6515 * @extends Roo.util.Observable
6516 * This is the default implementation of a ColumnModel used by the Grid. It defines
6517 * the columns in the grid.
6520 var colModel = new Roo.grid.ColumnModel([
6521 {header: "Ticker", width: 60, sortable: true, locked: true},
6522 {header: "Company Name", width: 150, sortable: true},
6523 {header: "Market Cap.", width: 100, sortable: true},
6524 {header: "$ Sales", width: 100, sortable: true, renderer: money},
6525 {header: "Employees", width: 100, sortable: true, resizable: false}
6530 * The config options listed for this class are options which may appear in each
6531 * individual column definition.
6532 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
6534 * @param {Object} config An Array of column config objects. See this class's
6535 * config objects for details.
6537 Roo.grid.ColumnModel = function(config){
6539 * The config passed into the constructor
6541 this.config = config;
6544 // if no id, create one
6545 // if the column does not have a dataIndex mapping,
6546 // map it to the order it is in the config
6547 for(var i = 0, len = config.length; i < len; i++){
6549 if(typeof c.dataIndex == "undefined"){
6552 if(typeof c.renderer == "string"){
6553 c.renderer = Roo.util.Format[c.renderer];
6555 if(typeof c.id == "undefined"){
6558 if(c.editor && c.editor.xtype){
6559 c.editor = Roo.factory(c.editor, Roo.grid);
6561 if(c.editor && c.editor.isFormField){
6562 c.editor = new Roo.grid.GridEditor(c.editor);
6564 this.lookup[c.id] = c;
6568 * The width of columns which have no width specified (defaults to 100)
6571 this.defaultWidth = 100;
6574 * Default sortable of columns which have no sortable specified (defaults to false)
6577 this.defaultSortable = false;
6581 * @event widthchange
6582 * Fires when the width of a column changes.
6583 * @param {ColumnModel} this
6584 * @param {Number} columnIndex The column index
6585 * @param {Number} newWidth The new width
6587 "widthchange": true,
6589 * @event headerchange
6590 * Fires when the text of a header changes.
6591 * @param {ColumnModel} this
6592 * @param {Number} columnIndex The column index
6593 * @param {Number} newText The new header text
6595 "headerchange": true,
6597 * @event hiddenchange
6598 * Fires when a column is hidden or "unhidden".
6599 * @param {ColumnModel} this
6600 * @param {Number} columnIndex The column index
6601 * @param {Boolean} hidden true if hidden, false otherwise
6603 "hiddenchange": true,
6605 * @event columnmoved
6606 * Fires when a column is moved.
6607 * @param {ColumnModel} this
6608 * @param {Number} oldIndex
6609 * @param {Number} newIndex
6611 "columnmoved" : true,
6613 * @event columlockchange
6614 * Fires when a column's locked state is changed
6615 * @param {ColumnModel} this
6616 * @param {Number} colIndex
6617 * @param {Boolean} locked true if locked
6619 "columnlockchange" : true
6621 Roo.grid.ColumnModel.superclass.constructor.call(this);
6623 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
6625 * @cfg {String} header The header text to display in the Grid view.
6628 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
6629 * {@link Roo.data.Record} definition from which to draw the column's value. If not
6630 * specified, the column's index is used as an index into the Record's data Array.
6633 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
6634 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
6637 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
6638 * Defaults to the value of the {@link #defaultSortable} property.
6639 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
6642 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
6645 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
6648 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
6651 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
6654 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
6655 * given the cell's data value. See {@link #setRenderer}. If not specified, the
6656 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
6657 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
6660 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
6663 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
6666 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
6669 * @cfg {String} cursor (Optional)
6672 * @cfg {String} tooltip (Optional)
6675 * @cfg {Number} xs (Optional)
6678 * @cfg {Number} sm (Optional)
6681 * @cfg {Number} md (Optional)
6684 * @cfg {Number} lg (Optional)
6687 * Returns the id of the column at the specified index.
6688 * @param {Number} index The column index
6689 * @return {String} the id
6691 getColumnId : function(index){
6692 return this.config[index].id;
6696 * Returns the column for a specified id.
6697 * @param {String} id The column id
6698 * @return {Object} the column
6700 getColumnById : function(id){
6701 return this.lookup[id];
6706 * Returns the column for a specified dataIndex.
6707 * @param {String} dataIndex The column dataIndex
6708 * @return {Object|Boolean} the column or false if not found
6710 getColumnByDataIndex: function(dataIndex){
6711 var index = this.findColumnIndex(dataIndex);
6712 return index > -1 ? this.config[index] : false;
6716 * Returns the index for a specified column id.
6717 * @param {String} id The column id
6718 * @return {Number} the index, or -1 if not found
6720 getIndexById : function(id){
6721 for(var i = 0, len = this.config.length; i < len; i++){
6722 if(this.config[i].id == id){
6730 * Returns the index for a specified column dataIndex.
6731 * @param {String} dataIndex The column dataIndex
6732 * @return {Number} the index, or -1 if not found
6735 findColumnIndex : function(dataIndex){
6736 for(var i = 0, len = this.config.length; i < len; i++){
6737 if(this.config[i].dataIndex == dataIndex){
6745 moveColumn : function(oldIndex, newIndex){
6746 var c = this.config[oldIndex];
6747 this.config.splice(oldIndex, 1);
6748 this.config.splice(newIndex, 0, c);
6749 this.dataMap = null;
6750 this.fireEvent("columnmoved", this, oldIndex, newIndex);
6753 isLocked : function(colIndex){
6754 return this.config[colIndex].locked === true;
6757 setLocked : function(colIndex, value, suppressEvent){
6758 if(this.isLocked(colIndex) == value){
6761 this.config[colIndex].locked = value;
6763 this.fireEvent("columnlockchange", this, colIndex, value);
6767 getTotalLockedWidth : function(){
6769 for(var i = 0; i < this.config.length; i++){
6770 if(this.isLocked(i) && !this.isHidden(i)){
6771 this.totalWidth += this.getColumnWidth(i);
6777 getLockedCount : function(){
6778 for(var i = 0, len = this.config.length; i < len; i++){
6779 if(!this.isLocked(i)){
6784 return this.config.length;
6788 * Returns the number of columns.
6791 getColumnCount : function(visibleOnly){
6792 if(visibleOnly === true){
6794 for(var i = 0, len = this.config.length; i < len; i++){
6795 if(!this.isHidden(i)){
6801 return this.config.length;
6805 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
6806 * @param {Function} fn
6807 * @param {Object} scope (optional)
6808 * @return {Array} result
6810 getColumnsBy : function(fn, scope){
6812 for(var i = 0, len = this.config.length; i < len; i++){
6813 var c = this.config[i];
6814 if(fn.call(scope||this, c, i) === true){
6822 * Returns true if the specified column is sortable.
6823 * @param {Number} col The column index
6826 isSortable : function(col){
6827 if(typeof this.config[col].sortable == "undefined"){
6828 return this.defaultSortable;
6830 return this.config[col].sortable;
6834 * Returns the rendering (formatting) function defined for the column.
6835 * @param {Number} col The column index.
6836 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
6838 getRenderer : function(col){
6839 if(!this.config[col].renderer){
6840 return Roo.grid.ColumnModel.defaultRenderer;
6842 return this.config[col].renderer;
6846 * Sets the rendering (formatting) function for a column.
6847 * @param {Number} col The column index
6848 * @param {Function} fn The function to use to process the cell's raw data
6849 * to return HTML markup for the grid view. The render function is called with
6850 * the following parameters:<ul>
6851 * <li>Data value.</li>
6852 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
6853 * <li>css A CSS style string to apply to the table cell.</li>
6854 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
6855 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
6856 * <li>Row index</li>
6857 * <li>Column index</li>
6858 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
6860 setRenderer : function(col, fn){
6861 this.config[col].renderer = fn;
6865 * Returns the width for the specified column.
6866 * @param {Number} col The column index
6869 getColumnWidth : function(col){
6870 return this.config[col].width * 1 || this.defaultWidth;
6874 * Sets the width for a column.
6875 * @param {Number} col The column index
6876 * @param {Number} width The new width
6878 setColumnWidth : function(col, width, suppressEvent){
6879 this.config[col].width = width;
6880 this.totalWidth = null;
6882 this.fireEvent("widthchange", this, col, width);
6887 * Returns the total width of all columns.
6888 * @param {Boolean} includeHidden True to include hidden column widths
6891 getTotalWidth : function(includeHidden){
6892 if(!this.totalWidth){
6893 this.totalWidth = 0;
6894 for(var i = 0, len = this.config.length; i < len; i++){
6895 if(includeHidden || !this.isHidden(i)){
6896 this.totalWidth += this.getColumnWidth(i);
6900 return this.totalWidth;
6904 * Returns the header for the specified column.
6905 * @param {Number} col The column index
6908 getColumnHeader : function(col){
6909 return this.config[col].header;
6913 * Sets the header for a column.
6914 * @param {Number} col The column index
6915 * @param {String} header The new header
6917 setColumnHeader : function(col, header){
6918 this.config[col].header = header;
6919 this.fireEvent("headerchange", this, col, header);
6923 * Returns the tooltip for the specified column.
6924 * @param {Number} col The column index
6927 getColumnTooltip : function(col){
6928 return this.config[col].tooltip;
6931 * Sets the tooltip for a column.
6932 * @param {Number} col The column index
6933 * @param {String} tooltip The new tooltip
6935 setColumnTooltip : function(col, tooltip){
6936 this.config[col].tooltip = tooltip;
6940 * Returns the dataIndex for the specified column.
6941 * @param {Number} col The column index
6944 getDataIndex : function(col){
6945 return this.config[col].dataIndex;
6949 * Sets the dataIndex for a column.
6950 * @param {Number} col The column index
6951 * @param {Number} dataIndex The new dataIndex
6953 setDataIndex : function(col, dataIndex){
6954 this.config[col].dataIndex = dataIndex;
6960 * Returns true if the cell is editable.
6961 * @param {Number} colIndex The column index
6962 * @param {Number} rowIndex The row index - this is nto actually used..?
6965 isCellEditable : function(colIndex, rowIndex){
6966 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6970 * Returns the editor defined for the cell/column.
6971 * return false or null to disable editing.
6972 * @param {Number} colIndex The column index
6973 * @param {Number} rowIndex The row index
6976 getCellEditor : function(colIndex, rowIndex){
6977 return this.config[colIndex].editor;
6981 * Sets if a column is editable.
6982 * @param {Number} col The column index
6983 * @param {Boolean} editable True if the column is editable
6985 setEditable : function(col, editable){
6986 this.config[col].editable = editable;
6991 * Returns true if the column is hidden.
6992 * @param {Number} colIndex The column index
6995 isHidden : function(colIndex){
6996 return this.config[colIndex].hidden;
7001 * Returns true if the column width cannot be changed
7003 isFixed : function(colIndex){
7004 return this.config[colIndex].fixed;
7008 * Returns true if the column can be resized
7011 isResizable : function(colIndex){
7012 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
7015 * Sets if a column is hidden.
7016 * @param {Number} colIndex The column index
7017 * @param {Boolean} hidden True if the column is hidden
7019 setHidden : function(colIndex, hidden){
7020 this.config[colIndex].hidden = hidden;
7021 this.totalWidth = null;
7022 this.fireEvent("hiddenchange", this, colIndex, hidden);
7026 * Sets the editor for a column.
7027 * @param {Number} col The column index
7028 * @param {Object} editor The editor object
7030 setEditor : function(col, editor){
7031 this.config[col].editor = editor;
7035 Roo.grid.ColumnModel.defaultRenderer = function(value)
7037 if(typeof value == "object") {
7040 if(typeof value == "string" && value.length < 1){
7044 return String.format("{0}", value);
7047 // Alias for backwards compatibility
7048 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
7051 * Ext JS Library 1.1.1
7052 * Copyright(c) 2006-2007, Ext JS, LLC.
7054 * Originally Released Under LGPL - original licence link has changed is not relivant.
7057 * <script type="text/javascript">
7061 * @class Roo.LoadMask
7062 * A simple utility class for generically masking elements while loading data. If the element being masked has
7063 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
7064 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
7065 * element's UpdateManager load indicator and will be destroyed after the initial load.
7067 * Create a new LoadMask
7068 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
7069 * @param {Object} config The config object
7071 Roo.LoadMask = function(el, config){
7072 this.el = Roo.get(el);
7073 Roo.apply(this, config);
7075 this.store.on('beforeload', this.onBeforeLoad, this);
7076 this.store.on('load', this.onLoad, this);
7077 this.store.on('loadexception', this.onLoadException, this);
7078 this.removeMask = false;
7080 var um = this.el.getUpdateManager();
7081 um.showLoadIndicator = false; // disable the default indicator
7082 um.on('beforeupdate', this.onBeforeLoad, this);
7083 um.on('update', this.onLoad, this);
7084 um.on('failure', this.onLoad, this);
7085 this.removeMask = true;
7089 Roo.LoadMask.prototype = {
7091 * @cfg {Boolean} removeMask
7092 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
7093 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
7097 * The text to display in a centered loading message box (defaults to 'Loading...')
7101 * @cfg {String} msgCls
7102 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
7104 msgCls : 'x-mask-loading',
7107 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
7113 * Disables the mask to prevent it from being displayed
7115 disable : function(){
7116 this.disabled = true;
7120 * Enables the mask so that it can be displayed
7122 enable : function(){
7123 this.disabled = false;
7126 onLoadException : function()
7130 if (typeof(arguments[3]) != 'undefined') {
7131 Roo.MessageBox.alert("Error loading",arguments[3]);
7135 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7136 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7143 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7148 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7152 onBeforeLoad : function(){
7154 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
7159 destroy : function(){
7161 this.store.un('beforeload', this.onBeforeLoad, this);
7162 this.store.un('load', this.onLoad, this);
7163 this.store.un('loadexception', this.onLoadException, this);
7165 var um = this.el.getUpdateManager();
7166 um.un('beforeupdate', this.onBeforeLoad, this);
7167 um.un('update', this.onLoad, this);
7168 um.un('failure', this.onLoad, this);
7179 * @class Roo.bootstrap.Table
7180 * @extends Roo.bootstrap.Component
7181 * Bootstrap Table class
7182 * @cfg {String} cls table class
7183 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
7184 * @cfg {String} bgcolor Specifies the background color for a table
7185 * @cfg {Number} border Specifies whether the table cells should have borders or not
7186 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
7187 * @cfg {Number} cellspacing Specifies the space between cells
7188 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
7189 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
7190 * @cfg {String} sortable Specifies that the table should be sortable
7191 * @cfg {String} summary Specifies a summary of the content of a table
7192 * @cfg {Number} width Specifies the width of a table
7193 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
7195 * @cfg {boolean} striped Should the rows be alternative striped
7196 * @cfg {boolean} bordered Add borders to the table
7197 * @cfg {boolean} hover Add hover highlighting
7198 * @cfg {boolean} condensed Format condensed
7199 * @cfg {boolean} responsive Format condensed
7200 * @cfg {Boolean} loadMask (true|false) default false
7201 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
7202 * @cfg {Boolean} headerShow (true|false) generate thead, default true
7203 * @cfg {Boolean} rowSelection (true|false) default false
7204 * @cfg {Boolean} cellSelection (true|false) default false
7205 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
7206 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
7207 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
7208 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
7212 * Create a new Table
7213 * @param {Object} config The config object
7216 Roo.bootstrap.Table = function(config){
7217 Roo.bootstrap.Table.superclass.constructor.call(this, config);
7222 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
7223 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
7224 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
7225 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
7227 this.sm = this.sm || {xtype: 'RowSelectionModel'};
7229 this.sm.grid = this;
7230 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
7231 this.sm = this.selModel;
7232 this.sm.xmodule = this.xmodule || false;
7235 if (this.cm && typeof(this.cm.config) == 'undefined') {
7236 this.colModel = new Roo.grid.ColumnModel(this.cm);
7237 this.cm = this.colModel;
7238 this.cm.xmodule = this.xmodule || false;
7241 this.store= Roo.factory(this.store, Roo.data);
7242 this.ds = this.store;
7243 this.ds.xmodule = this.xmodule || false;
7246 if (this.footer && this.store) {
7247 this.footer.dataSource = this.ds;
7248 this.footer = Roo.factory(this.footer);
7255 * Fires when a cell is clicked
7256 * @param {Roo.bootstrap.Table} this
7257 * @param {Roo.Element} el
7258 * @param {Number} rowIndex
7259 * @param {Number} columnIndex
7260 * @param {Roo.EventObject} e
7264 * @event celldblclick
7265 * Fires when a cell is double clicked
7266 * @param {Roo.bootstrap.Table} this
7267 * @param {Roo.Element} el
7268 * @param {Number} rowIndex
7269 * @param {Number} columnIndex
7270 * @param {Roo.EventObject} e
7272 "celldblclick" : true,
7275 * Fires when a row is clicked
7276 * @param {Roo.bootstrap.Table} this
7277 * @param {Roo.Element} el
7278 * @param {Number} rowIndex
7279 * @param {Roo.EventObject} e
7283 * @event rowdblclick
7284 * Fires when a row is double clicked
7285 * @param {Roo.bootstrap.Table} this
7286 * @param {Roo.Element} el
7287 * @param {Number} rowIndex
7288 * @param {Roo.EventObject} e
7290 "rowdblclick" : true,
7293 * Fires when a mouseover occur
7294 * @param {Roo.bootstrap.Table} this
7295 * @param {Roo.Element} el
7296 * @param {Number} rowIndex
7297 * @param {Number} columnIndex
7298 * @param {Roo.EventObject} e
7303 * Fires when a mouseout occur
7304 * @param {Roo.bootstrap.Table} this
7305 * @param {Roo.Element} el
7306 * @param {Number} rowIndex
7307 * @param {Number} columnIndex
7308 * @param {Roo.EventObject} e
7313 * Fires when a row is rendered, so you can change add a style to it.
7314 * @param {Roo.bootstrap.Table} this
7315 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
7319 * @event rowsrendered
7320 * Fires when all the rows have been rendered
7321 * @param {Roo.bootstrap.Table} this
7323 'rowsrendered' : true,
7325 * @event contextmenu
7326 * The raw contextmenu event for the entire grid.
7327 * @param {Roo.EventObject} e
7329 "contextmenu" : true,
7331 * @event rowcontextmenu
7332 * Fires when a row is right clicked
7333 * @param {Roo.bootstrap.Table} this
7334 * @param {Number} rowIndex
7335 * @param {Roo.EventObject} e
7337 "rowcontextmenu" : true,
7339 * @event cellcontextmenu
7340 * Fires when a cell is right clicked
7341 * @param {Roo.bootstrap.Table} this
7342 * @param {Number} rowIndex
7343 * @param {Number} cellIndex
7344 * @param {Roo.EventObject} e
7346 "cellcontextmenu" : true,
7348 * @event headercontextmenu
7349 * Fires when a header is right clicked
7350 * @param {Roo.bootstrap.Table} this
7351 * @param {Number} columnIndex
7352 * @param {Roo.EventObject} e
7354 "headercontextmenu" : true
7358 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
7384 rowSelection : false,
7385 cellSelection : false,
7388 // Roo.Element - the tbody
7390 // Roo.Element - thead element
7393 container: false, // used by gridpanel...
7399 auto_hide_footer : false,
7401 getAutoCreate : function()
7403 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
7410 if (this.scrollBody) {
7411 cfg.cls += ' table-body-fixed';
7414 cfg.cls += ' table-striped';
7418 cfg.cls += ' table-hover';
7420 if (this.bordered) {
7421 cfg.cls += ' table-bordered';
7423 if (this.condensed) {
7424 cfg.cls += ' table-condensed';
7426 if (this.responsive) {
7427 cfg.cls += ' table-responsive';
7431 cfg.cls+= ' ' +this.cls;
7434 // this lot should be simplifed...
7447 ].forEach(function(k) {
7455 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
7458 if(this.store || this.cm){
7459 if(this.headerShow){
7460 cfg.cn.push(this.renderHeader());
7463 cfg.cn.push(this.renderBody());
7465 if(this.footerShow){
7466 cfg.cn.push(this.renderFooter());
7468 // where does this come from?
7469 //cfg.cls+= ' TableGrid';
7472 return { cn : [ cfg ] };
7475 initEvents : function()
7477 if(!this.store || !this.cm){
7480 if (this.selModel) {
7481 this.selModel.initEvents();
7485 //Roo.log('initEvents with ds!!!!');
7487 this.mainBody = this.el.select('tbody', true).first();
7488 this.mainHead = this.el.select('thead', true).first();
7489 this.mainFoot = this.el.select('tfoot', true).first();
7495 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7496 e.on('click', _this.sort, _this);
7499 this.mainBody.on("click", this.onClick, this);
7500 this.mainBody.on("dblclick", this.onDblClick, this);
7502 // why is this done????? = it breaks dialogs??
7503 //this.parent().el.setStyle('position', 'relative');
7507 this.footer.parentId = this.id;
7508 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
7511 this.el.select('tfoot tr td').first().addClass('hide');
7516 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
7519 this.store.on('load', this.onLoad, this);
7520 this.store.on('beforeload', this.onBeforeLoad, this);
7521 this.store.on('update', this.onUpdate, this);
7522 this.store.on('add', this.onAdd, this);
7523 this.store.on("clear", this.clear, this);
7525 this.el.on("contextmenu", this.onContextMenu, this);
7527 this.mainBody.on('scroll', this.onBodyScroll, this);
7529 this.cm.on("headerchange", this.onHeaderChange, this);
7531 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
7535 onContextMenu : function(e, t)
7537 this.processEvent("contextmenu", e);
7540 processEvent : function(name, e)
7542 if (name != 'touchstart' ) {
7543 this.fireEvent(name, e);
7546 var t = e.getTarget();
7548 var cell = Roo.get(t);
7554 if(cell.findParent('tfoot', false, true)){
7558 if(cell.findParent('thead', false, true)){
7560 if(e.getTarget().nodeName.toLowerCase() != 'th'){
7561 cell = Roo.get(t).findParent('th', false, true);
7563 Roo.log("failed to find th in thead?");
7564 Roo.log(e.getTarget());
7569 var cellIndex = cell.dom.cellIndex;
7571 var ename = name == 'touchstart' ? 'click' : name;
7572 this.fireEvent("header" + ename, this, cellIndex, e);
7577 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7578 cell = Roo.get(t).findParent('td', false, true);
7580 Roo.log("failed to find th in tbody?");
7581 Roo.log(e.getTarget());
7586 var row = cell.findParent('tr', false, true);
7587 var cellIndex = cell.dom.cellIndex;
7588 var rowIndex = row.dom.rowIndex - 1;
7592 this.fireEvent("row" + name, this, rowIndex, e);
7596 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
7602 onMouseover : function(e, el)
7604 var cell = Roo.get(el);
7610 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7611 cell = cell.findParent('td', false, true);
7614 var row = cell.findParent('tr', false, true);
7615 var cellIndex = cell.dom.cellIndex;
7616 var rowIndex = row.dom.rowIndex - 1; // start from 0
7618 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
7622 onMouseout : function(e, el)
7624 var cell = Roo.get(el);
7630 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7631 cell = cell.findParent('td', false, true);
7634 var row = cell.findParent('tr', false, true);
7635 var cellIndex = cell.dom.cellIndex;
7636 var rowIndex = row.dom.rowIndex - 1; // start from 0
7638 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
7642 onClick : function(e, el)
7644 var cell = Roo.get(el);
7646 if(!cell || (!this.cellSelection && !this.rowSelection)){
7650 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7651 cell = cell.findParent('td', false, true);
7654 if(!cell || typeof(cell) == 'undefined'){
7658 var row = cell.findParent('tr', false, true);
7660 if(!row || typeof(row) == 'undefined'){
7664 var cellIndex = cell.dom.cellIndex;
7665 var rowIndex = this.getRowIndex(row);
7667 // why??? - should these not be based on SelectionModel?
7668 if(this.cellSelection){
7669 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
7672 if(this.rowSelection){
7673 this.fireEvent('rowclick', this, row, rowIndex, e);
7679 onDblClick : function(e,el)
7681 var cell = Roo.get(el);
7683 if(!cell || (!this.cellSelection && !this.rowSelection)){
7687 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7688 cell = cell.findParent('td', false, true);
7691 if(!cell || typeof(cell) == 'undefined'){
7695 var row = cell.findParent('tr', false, true);
7697 if(!row || typeof(row) == 'undefined'){
7701 var cellIndex = cell.dom.cellIndex;
7702 var rowIndex = this.getRowIndex(row);
7704 if(this.cellSelection){
7705 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
7708 if(this.rowSelection){
7709 this.fireEvent('rowdblclick', this, row, rowIndex, e);
7713 sort : function(e,el)
7715 var col = Roo.get(el);
7717 if(!col.hasClass('sortable')){
7721 var sort = col.attr('sort');
7724 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
7728 this.store.sortInfo = {field : sort, direction : dir};
7731 Roo.log("calling footer first");
7732 this.footer.onClick('first');
7735 this.store.load({ params : { start : 0 } });
7739 renderHeader : function()
7747 this.totalWidth = 0;
7749 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7751 var config = cm.config[i];
7755 cls : 'x-hcol-' + i,
7757 html: cm.getColumnHeader(i)
7762 if(typeof(config.sortable) != 'undefined' && config.sortable){
7764 c.html = '<i class="glyphicon"></i>' + c.html;
7767 // could use BS4 hidden-..-down
7769 if(typeof(config.lgHeader) != 'undefined'){
7770 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
7773 if(typeof(config.mdHeader) != 'undefined'){
7774 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
7777 if(typeof(config.smHeader) != 'undefined'){
7778 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
7781 if(typeof(config.xsHeader) != 'undefined'){
7782 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
7789 if(typeof(config.tooltip) != 'undefined'){
7790 c.tooltip = config.tooltip;
7793 if(typeof(config.colspan) != 'undefined'){
7794 c.colspan = config.colspan;
7797 if(typeof(config.hidden) != 'undefined' && config.hidden){
7798 c.style += ' display:none;';
7801 if(typeof(config.dataIndex) != 'undefined'){
7802 c.sort = config.dataIndex;
7807 if(typeof(config.align) != 'undefined' && config.align.length){
7808 c.style += ' text-align:' + config.align + ';';
7811 if(typeof(config.width) != 'undefined'){
7812 c.style += ' width:' + config.width + 'px;';
7813 this.totalWidth += config.width;
7815 this.totalWidth += 100; // assume minimum of 100 per column?
7818 if(typeof(config.cls) != 'undefined'){
7819 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
7822 ['xs','sm','md','lg'].map(function(size){
7824 if(typeof(config[size]) == 'undefined'){
7828 if (!config[size]) { // 0 = hidden
7829 // BS 4 '0' is treated as hide that column and below.
7830 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
7834 c.cls += ' col-' + size + '-' + config[size] + (
7835 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7847 renderBody : function()
7857 colspan : this.cm.getColumnCount()
7867 renderFooter : function()
7877 colspan : this.cm.getColumnCount()
7891 // Roo.log('ds onload');
7896 var ds = this.store;
7898 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7899 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
7900 if (_this.store.sortInfo) {
7902 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
7903 e.select('i', true).addClass(['glyphicon-arrow-up']);
7906 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
7907 e.select('i', true).addClass(['glyphicon-arrow-down']);
7912 var tbody = this.mainBody;
7914 if(ds.getCount() > 0){
7915 ds.data.each(function(d,rowIndex){
7916 var row = this.renderRow(cm, ds, rowIndex);
7918 tbody.createChild(row);
7922 if(row.cellObjects.length){
7923 Roo.each(row.cellObjects, function(r){
7924 _this.renderCellObject(r);
7931 var tfoot = this.el.select('tfoot', true).first();
7933 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7935 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7937 var total = this.ds.getTotalCount();
7939 if(this.footer.pageSize < total){
7940 this.mainFoot.show();
7944 Roo.each(this.el.select('tbody td', true).elements, function(e){
7945 e.on('mouseover', _this.onMouseover, _this);
7948 Roo.each(this.el.select('tbody td', true).elements, function(e){
7949 e.on('mouseout', _this.onMouseout, _this);
7951 this.fireEvent('rowsrendered', this);
7957 onUpdate : function(ds,record)
7959 this.refreshRow(record);
7963 onRemove : function(ds, record, index, isUpdate){
7964 if(isUpdate !== true){
7965 this.fireEvent("beforerowremoved", this, index, record);
7967 var bt = this.mainBody.dom;
7969 var rows = this.el.select('tbody > tr', true).elements;
7971 if(typeof(rows[index]) != 'undefined'){
7972 bt.removeChild(rows[index].dom);
7975 // if(bt.rows[index]){
7976 // bt.removeChild(bt.rows[index]);
7979 if(isUpdate !== true){
7980 //this.stripeRows(index);
7981 //this.syncRowHeights(index, index);
7983 this.fireEvent("rowremoved", this, index, record);
7987 onAdd : function(ds, records, rowIndex)
7989 //Roo.log('on Add called');
7990 // - note this does not handle multiple adding very well..
7991 var bt = this.mainBody.dom;
7992 for (var i =0 ; i < records.length;i++) {
7993 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7994 //Roo.log(records[i]);
7995 //Roo.log(this.store.getAt(rowIndex+i));
7996 this.insertRow(this.store, rowIndex + i, false);
8003 refreshRow : function(record){
8004 var ds = this.store, index;
8005 if(typeof record == 'number'){
8007 record = ds.getAt(index);
8009 index = ds.indexOf(record);
8011 this.insertRow(ds, index, true);
8013 this.onRemove(ds, record, index+1, true);
8015 //this.syncRowHeights(index, index);
8017 this.fireEvent("rowupdated", this, index, record);
8020 insertRow : function(dm, rowIndex, isUpdate){
8023 this.fireEvent("beforerowsinserted", this, rowIndex);
8025 //var s = this.getScrollState();
8026 var row = this.renderRow(this.cm, this.store, rowIndex);
8027 // insert before rowIndex..
8028 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
8032 if(row.cellObjects.length){
8033 Roo.each(row.cellObjects, function(r){
8034 _this.renderCellObject(r);
8039 this.fireEvent("rowsinserted", this, rowIndex);
8040 //this.syncRowHeights(firstRow, lastRow);
8041 //this.stripeRows(firstRow);
8048 getRowDom : function(rowIndex)
8050 var rows = this.el.select('tbody > tr', true).elements;
8052 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
8055 // returns the object tree for a tr..
8058 renderRow : function(cm, ds, rowIndex)
8060 var d = ds.getAt(rowIndex);
8064 cls : 'x-row-' + rowIndex,
8068 var cellObjects = [];
8070 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8071 var config = cm.config[i];
8073 var renderer = cm.getRenderer(i);
8077 if(typeof(renderer) !== 'undefined'){
8078 value = renderer(d.data[cm.getDataIndex(i)], false, d);
8080 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
8081 // and are rendered into the cells after the row is rendered - using the id for the element.
8083 if(typeof(value) === 'object'){
8093 rowIndex : rowIndex,
8098 this.fireEvent('rowclass', this, rowcfg);
8102 cls : rowcfg.rowClass + ' x-col-' + i,
8104 html: (typeof(value) === 'object') ? '' : value
8111 if(typeof(config.colspan) != 'undefined'){
8112 td.colspan = config.colspan;
8115 if(typeof(config.hidden) != 'undefined' && config.hidden){
8116 td.style += ' display:none;';
8119 if(typeof(config.align) != 'undefined' && config.align.length){
8120 td.style += ' text-align:' + config.align + ';';
8122 if(typeof(config.valign) != 'undefined' && config.valign.length){
8123 td.style += ' vertical-align:' + config.valign + ';';
8126 if(typeof(config.width) != 'undefined'){
8127 td.style += ' width:' + config.width + 'px;';
8130 if(typeof(config.cursor) != 'undefined'){
8131 td.style += ' cursor:' + config.cursor + ';';
8134 if(typeof(config.cls) != 'undefined'){
8135 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
8138 ['xs','sm','md','lg'].map(function(size){
8140 if(typeof(config[size]) == 'undefined'){
8146 if (!config[size]) { // 0 = hidden
8147 // BS 4 '0' is treated as hide that column and below.
8148 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
8152 td.cls += ' col-' + size + '-' + config[size] + (
8153 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8163 row.cellObjects = cellObjects;
8171 onBeforeLoad : function()
8180 this.el.select('tbody', true).first().dom.innerHTML = '';
8183 * Show or hide a row.
8184 * @param {Number} rowIndex to show or hide
8185 * @param {Boolean} state hide
8187 setRowVisibility : function(rowIndex, state)
8189 var bt = this.mainBody.dom;
8191 var rows = this.el.select('tbody > tr', true).elements;
8193 if(typeof(rows[rowIndex]) == 'undefined'){
8196 rows[rowIndex].dom.style.display = state ? '' : 'none';
8200 getSelectionModel : function(){
8202 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
8204 return this.selModel;
8207 * Render the Roo.bootstrap object from renderder
8209 renderCellObject : function(r)
8213 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
8215 var t = r.cfg.render(r.container);
8218 Roo.each(r.cfg.cn, function(c){
8220 container: t.getChildContainer(),
8223 _this.renderCellObject(child);
8228 getRowIndex : function(row)
8232 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
8243 * Returns the grid's underlying element = used by panel.Grid
8244 * @return {Element} The element
8246 getGridEl : function(){
8250 * Forces a resize - used by panel.Grid
8251 * @return {Element} The element
8253 autoSize : function()
8255 //var ctr = Roo.get(this.container.dom.parentElement);
8256 var ctr = Roo.get(this.el.dom);
8258 var thd = this.getGridEl().select('thead',true).first();
8259 var tbd = this.getGridEl().select('tbody', true).first();
8260 var tfd = this.getGridEl().select('tfoot', true).first();
8262 var cw = ctr.getWidth();
8266 tbd.setWidth(ctr.getWidth());
8267 // if the body has a max height - and then scrolls - we should perhaps set up the height here
8268 // this needs fixing for various usage - currently only hydra job advers I think..
8270 // ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
8272 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
8275 cw = Math.max(cw, this.totalWidth);
8276 this.getGridEl().select('tr',true).setWidth(cw);
8277 // resize 'expandable coloumn?
8279 return; // we doe not have a view in this design..
8282 onBodyScroll: function()
8284 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
8286 this.mainHead.setStyle({
8287 'position' : 'relative',
8288 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
8294 var scrollHeight = this.mainBody.dom.scrollHeight;
8296 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
8298 var height = this.mainBody.getHeight();
8300 if(scrollHeight - height == scrollTop) {
8302 var total = this.ds.getTotalCount();
8304 if(this.footer.cursor + this.footer.pageSize < total){
8306 this.footer.ds.load({
8308 start : this.footer.cursor + this.footer.pageSize,
8309 limit : this.footer.pageSize
8319 onHeaderChange : function()
8321 var header = this.renderHeader();
8322 var table = this.el.select('table', true).first();
8324 this.mainHead.remove();
8325 this.mainHead = table.createChild(header, this.mainBody, false);
8328 onHiddenChange : function(colModel, colIndex, hidden)
8330 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
8331 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
8333 this.CSS.updateRule(thSelector, "display", "");
8334 this.CSS.updateRule(tdSelector, "display", "");
8337 this.CSS.updateRule(thSelector, "display", "none");
8338 this.CSS.updateRule(tdSelector, "display", "none");
8341 this.onHeaderChange();
8345 setColumnWidth: function(col_index, width)
8347 // width = "md-2 xs-2..."
8348 if(!this.colModel.config[col_index]) {
8352 var w = width.split(" ");
8354 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
8356 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
8359 for(var j = 0; j < w.length; j++) {
8365 var size_cls = w[j].split("-");
8367 if(!Number.isInteger(size_cls[1] * 1)) {
8371 if(!this.colModel.config[col_index][size_cls[0]]) {
8375 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8379 h_row[0].classList.replace(
8380 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8381 "col-"+size_cls[0]+"-"+size_cls[1]
8384 for(var i = 0; i < rows.length; i++) {
8386 var size_cls = w[j].split("-");
8388 if(!Number.isInteger(size_cls[1] * 1)) {
8392 if(!this.colModel.config[col_index][size_cls[0]]) {
8396 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8400 rows[i].classList.replace(
8401 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8402 "col-"+size_cls[0]+"-"+size_cls[1]
8406 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
8421 * @class Roo.bootstrap.TableCell
8422 * @extends Roo.bootstrap.Component
8423 * Bootstrap TableCell class
8424 * @cfg {String} html cell contain text
8425 * @cfg {String} cls cell class
8426 * @cfg {String} tag cell tag (td|th) default td
8427 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
8428 * @cfg {String} align Aligns the content in a cell
8429 * @cfg {String} axis Categorizes cells
8430 * @cfg {String} bgcolor Specifies the background color of a cell
8431 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8432 * @cfg {Number} colspan Specifies the number of columns a cell should span
8433 * @cfg {String} headers Specifies one or more header cells a cell is related to
8434 * @cfg {Number} height Sets the height of a cell
8435 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
8436 * @cfg {Number} rowspan Sets the number of rows a cell should span
8437 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
8438 * @cfg {String} valign Vertical aligns the content in a cell
8439 * @cfg {Number} width Specifies the width of a cell
8442 * Create a new TableCell
8443 * @param {Object} config The config object
8446 Roo.bootstrap.TableCell = function(config){
8447 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
8450 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
8470 getAutoCreate : function(){
8471 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
8491 cfg.align=this.align
8497 cfg.bgcolor=this.bgcolor
8500 cfg.charoff=this.charoff
8503 cfg.colspan=this.colspan
8506 cfg.headers=this.headers
8509 cfg.height=this.height
8512 cfg.nowrap=this.nowrap
8515 cfg.rowspan=this.rowspan
8518 cfg.scope=this.scope
8521 cfg.valign=this.valign
8524 cfg.width=this.width
8543 * @class Roo.bootstrap.TableRow
8544 * @extends Roo.bootstrap.Component
8545 * Bootstrap TableRow class
8546 * @cfg {String} cls row class
8547 * @cfg {String} align Aligns the content in a table row
8548 * @cfg {String} bgcolor Specifies a background color for a table row
8549 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8550 * @cfg {String} valign Vertical aligns the content in a table row
8553 * Create a new TableRow
8554 * @param {Object} config The config object
8557 Roo.bootstrap.TableRow = function(config){
8558 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
8561 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
8569 getAutoCreate : function(){
8570 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
8580 cfg.align = this.align;
8583 cfg.bgcolor = this.bgcolor;
8586 cfg.charoff = this.charoff;
8589 cfg.valign = this.valign;
8607 * @class Roo.bootstrap.TableBody
8608 * @extends Roo.bootstrap.Component
8609 * Bootstrap TableBody class
8610 * @cfg {String} cls element class
8611 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
8612 * @cfg {String} align Aligns the content inside the element
8613 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
8614 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
8617 * Create a new TableBody
8618 * @param {Object} config The config object
8621 Roo.bootstrap.TableBody = function(config){
8622 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
8625 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
8633 getAutoCreate : function(){
8634 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
8648 cfg.align = this.align;
8651 cfg.charoff = this.charoff;
8654 cfg.valign = this.valign;
8661 // initEvents : function()
8668 // this.store = Roo.factory(this.store, Roo.data);
8669 // this.store.on('load', this.onLoad, this);
8671 // this.store.load();
8675 // onLoad: function ()
8677 // this.fireEvent('load', this);
8687 * Ext JS Library 1.1.1
8688 * Copyright(c) 2006-2007, Ext JS, LLC.
8690 * Originally Released Under LGPL - original licence link has changed is not relivant.
8693 * <script type="text/javascript">
8696 // as we use this in bootstrap.
8697 Roo.namespace('Roo.form');
8699 * @class Roo.form.Action
8700 * Internal Class used to handle form actions
8702 * @param {Roo.form.BasicForm} el The form element or its id
8703 * @param {Object} config Configuration options
8708 // define the action interface
8709 Roo.form.Action = function(form, options){
8711 this.options = options || {};
8714 * Client Validation Failed
8717 Roo.form.Action.CLIENT_INVALID = 'client';
8719 * Server Validation Failed
8722 Roo.form.Action.SERVER_INVALID = 'server';
8724 * Connect to Server Failed
8727 Roo.form.Action.CONNECT_FAILURE = 'connect';
8729 * Reading Data from Server Failed
8732 Roo.form.Action.LOAD_FAILURE = 'load';
8734 Roo.form.Action.prototype = {
8736 failureType : undefined,
8737 response : undefined,
8741 run : function(options){
8746 success : function(response){
8751 handleResponse : function(response){
8755 // default connection failure
8756 failure : function(response){
8758 this.response = response;
8759 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8760 this.form.afterAction(this, false);
8763 processResponse : function(response){
8764 this.response = response;
8765 if(!response.responseText){
8768 this.result = this.handleResponse(response);
8772 // utility functions used internally
8773 getUrl : function(appendParams){
8774 var url = this.options.url || this.form.url || this.form.el.dom.action;
8776 var p = this.getParams();
8778 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
8784 getMethod : function(){
8785 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
8788 getParams : function(){
8789 var bp = this.form.baseParams;
8790 var p = this.options.params;
8792 if(typeof p == "object"){
8793 p = Roo.urlEncode(Roo.applyIf(p, bp));
8794 }else if(typeof p == 'string' && bp){
8795 p += '&' + Roo.urlEncode(bp);
8798 p = Roo.urlEncode(bp);
8803 createCallback : function(){
8805 success: this.success,
8806 failure: this.failure,
8808 timeout: (this.form.timeout*1000),
8809 upload: this.form.fileUpload ? this.success : undefined
8814 Roo.form.Action.Submit = function(form, options){
8815 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
8818 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
8821 haveProgress : false,
8822 uploadComplete : false,
8824 // uploadProgress indicator.
8825 uploadProgress : function()
8827 if (!this.form.progressUrl) {
8831 if (!this.haveProgress) {
8832 Roo.MessageBox.progress("Uploading", "Uploading");
8834 if (this.uploadComplete) {
8835 Roo.MessageBox.hide();
8839 this.haveProgress = true;
8841 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
8843 var c = new Roo.data.Connection();
8845 url : this.form.progressUrl,
8850 success : function(req){
8851 //console.log(data);
8855 rdata = Roo.decode(req.responseText)
8857 Roo.log("Invalid data from server..");
8861 if (!rdata || !rdata.success) {
8863 Roo.MessageBox.alert(Roo.encode(rdata));
8866 var data = rdata.data;
8868 if (this.uploadComplete) {
8869 Roo.MessageBox.hide();
8874 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
8875 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
8878 this.uploadProgress.defer(2000,this);
8881 failure: function(data) {
8882 Roo.log('progress url failed ');
8893 // run get Values on the form, so it syncs any secondary forms.
8894 this.form.getValues();
8896 var o = this.options;
8897 var method = this.getMethod();
8898 var isPost = method == 'POST';
8899 if(o.clientValidation === false || this.form.isValid()){
8901 if (this.form.progressUrl) {
8902 this.form.findField('UPLOAD_IDENTIFIER').setValue(
8903 (new Date() * 1) + '' + Math.random());
8908 Roo.Ajax.request(Roo.apply(this.createCallback(), {
8909 form:this.form.el.dom,
8910 url:this.getUrl(!isPost),
8912 params:isPost ? this.getParams() : null,
8913 isUpload: this.form.fileUpload,
8914 formData : this.form.formData
8917 this.uploadProgress();
8919 }else if (o.clientValidation !== false){ // client validation failed
8920 this.failureType = Roo.form.Action.CLIENT_INVALID;
8921 this.form.afterAction(this, false);
8925 success : function(response)
8927 this.uploadComplete= true;
8928 if (this.haveProgress) {
8929 Roo.MessageBox.hide();
8933 var result = this.processResponse(response);
8934 if(result === true || result.success){
8935 this.form.afterAction(this, true);
8939 this.form.markInvalid(result.errors);
8940 this.failureType = Roo.form.Action.SERVER_INVALID;
8942 this.form.afterAction(this, false);
8944 failure : function(response)
8946 this.uploadComplete= true;
8947 if (this.haveProgress) {
8948 Roo.MessageBox.hide();
8951 this.response = response;
8952 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8953 this.form.afterAction(this, false);
8956 handleResponse : function(response){
8957 if(this.form.errorReader){
8958 var rs = this.form.errorReader.read(response);
8961 for(var i = 0, len = rs.records.length; i < len; i++) {
8962 var r = rs.records[i];
8966 if(errors.length < 1){
8970 success : rs.success,
8976 ret = Roo.decode(response.responseText);
8980 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8990 Roo.form.Action.Load = function(form, options){
8991 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8992 this.reader = this.form.reader;
8995 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
9000 Roo.Ajax.request(Roo.apply(
9001 this.createCallback(), {
9002 method:this.getMethod(),
9003 url:this.getUrl(false),
9004 params:this.getParams()
9008 success : function(response){
9010 var result = this.processResponse(response);
9011 if(result === true || !result.success || !result.data){
9012 this.failureType = Roo.form.Action.LOAD_FAILURE;
9013 this.form.afterAction(this, false);
9016 this.form.clearInvalid();
9017 this.form.setValues(result.data);
9018 this.form.afterAction(this, true);
9021 handleResponse : function(response){
9022 if(this.form.reader){
9023 var rs = this.form.reader.read(response);
9024 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
9026 success : rs.success,
9030 return Roo.decode(response.responseText);
9034 Roo.form.Action.ACTION_TYPES = {
9035 'load' : Roo.form.Action.Load,
9036 'submit' : Roo.form.Action.Submit
9045 * @class Roo.bootstrap.Form
9046 * @extends Roo.bootstrap.Component
9047 * Bootstrap Form class
9048 * @cfg {String} method GET | POST (default POST)
9049 * @cfg {String} labelAlign top | left (default top)
9050 * @cfg {String} align left | right - for navbars
9051 * @cfg {Boolean} loadMask load mask when submit (default true)
9056 * @param {Object} config The config object
9060 Roo.bootstrap.Form = function(config){
9062 Roo.bootstrap.Form.superclass.constructor.call(this, config);
9064 Roo.bootstrap.Form.popover.apply();
9068 * @event clientvalidation
9069 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
9070 * @param {Form} this
9071 * @param {Boolean} valid true if the form has passed client-side validation
9073 clientvalidation: true,
9075 * @event beforeaction
9076 * Fires before any action is performed. Return false to cancel the action.
9077 * @param {Form} this
9078 * @param {Action} action The action to be performed
9082 * @event actionfailed
9083 * Fires when an action fails.
9084 * @param {Form} this
9085 * @param {Action} action The action that failed
9087 actionfailed : true,
9089 * @event actioncomplete
9090 * Fires when an action is completed.
9091 * @param {Form} this
9092 * @param {Action} action The action that completed
9094 actioncomplete : true
9098 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
9101 * @cfg {String} method
9102 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
9107 * The URL to use for form actions if one isn't supplied in the action options.
9110 * @cfg {Boolean} fileUpload
9111 * Set to true if this form is a file upload.
9115 * @cfg {Object} baseParams
9116 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
9120 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
9124 * @cfg {Sting} align (left|right) for navbar forms
9129 activeAction : null,
9132 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
9133 * element by passing it or its id or mask the form itself by passing in true.
9136 waitMsgTarget : false,
9141 * @cfg {Boolean} errorMask (true|false) default false
9146 * @cfg {Number} maskOffset Default 100
9151 * @cfg {Boolean} maskBody
9155 getAutoCreate : function(){
9159 method : this.method || 'POST',
9160 id : this.id || Roo.id(),
9163 if (this.parent().xtype.match(/^Nav/)) {
9164 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
9168 if (this.labelAlign == 'left' ) {
9169 cfg.cls += ' form-horizontal';
9175 initEvents : function()
9177 this.el.on('submit', this.onSubmit, this);
9178 // this was added as random key presses on the form where triggering form submit.
9179 this.el.on('keypress', function(e) {
9180 if (e.getCharCode() != 13) {
9183 // we might need to allow it for textareas.. and some other items.
9184 // check e.getTarget().
9186 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
9190 Roo.log("keypress blocked");
9198 onSubmit : function(e){
9203 * Returns true if client-side validation on the form is successful.
9206 isValid : function(){
9207 var items = this.getItems();
9211 items.each(function(f){
9217 Roo.log('invalid field: ' + f.name);
9221 if(!target && f.el.isVisible(true)){
9227 if(this.errorMask && !valid){
9228 Roo.bootstrap.Form.popover.mask(this, target);
9235 * Returns true if any fields in this form have changed since their original load.
9238 isDirty : function(){
9240 var items = this.getItems();
9241 items.each(function(f){
9251 * Performs a predefined action (submit or load) or custom actions you define on this form.
9252 * @param {String} actionName The name of the action type
9253 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
9254 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
9255 * accept other config options):
9257 Property Type Description
9258 ---------------- --------------- ----------------------------------------------------------------------------------
9259 url String The url for the action (defaults to the form's url)
9260 method String The form method to use (defaults to the form's method, or POST if not defined)
9261 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
9262 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
9263 validate the form on the client (defaults to false)
9265 * @return {BasicForm} this
9267 doAction : function(action, options){
9268 if(typeof action == 'string'){
9269 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
9271 if(this.fireEvent('beforeaction', this, action) !== false){
9272 this.beforeAction(action);
9273 action.run.defer(100, action);
9279 beforeAction : function(action){
9280 var o = action.options;
9285 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
9287 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9290 // not really supported yet.. ??
9292 //if(this.waitMsgTarget === true){
9293 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9294 //}else if(this.waitMsgTarget){
9295 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
9296 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
9298 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
9304 afterAction : function(action, success){
9305 this.activeAction = null;
9306 var o = action.options;
9311 Roo.get(document.body).unmask();
9317 //if(this.waitMsgTarget === true){
9318 // this.el.unmask();
9319 //}else if(this.waitMsgTarget){
9320 // this.waitMsgTarget.unmask();
9322 // Roo.MessageBox.updateProgress(1);
9323 // Roo.MessageBox.hide();
9330 Roo.callback(o.success, o.scope, [this, action]);
9331 this.fireEvent('actioncomplete', this, action);
9335 // failure condition..
9336 // we have a scenario where updates need confirming.
9337 // eg. if a locking scenario exists..
9338 // we look for { errors : { needs_confirm : true }} in the response.
9340 (typeof(action.result) != 'undefined') &&
9341 (typeof(action.result.errors) != 'undefined') &&
9342 (typeof(action.result.errors.needs_confirm) != 'undefined')
9345 Roo.log("not supported yet");
9348 Roo.MessageBox.confirm(
9349 "Change requires confirmation",
9350 action.result.errorMsg,
9355 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
9365 Roo.callback(o.failure, o.scope, [this, action]);
9366 // show an error message if no failed handler is set..
9367 if (!this.hasListener('actionfailed')) {
9368 Roo.log("need to add dialog support");
9370 Roo.MessageBox.alert("Error",
9371 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
9372 action.result.errorMsg :
9373 "Saving Failed, please check your entries or try again"
9378 this.fireEvent('actionfailed', this, action);
9383 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
9384 * @param {String} id The value to search for
9387 findField : function(id){
9388 var items = this.getItems();
9389 var field = items.get(id);
9391 items.each(function(f){
9392 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
9399 return field || null;
9402 * Mark fields in this form invalid in bulk.
9403 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
9404 * @return {BasicForm} this
9406 markInvalid : function(errors){
9407 if(errors instanceof Array){
9408 for(var i = 0, len = errors.length; i < len; i++){
9409 var fieldError = errors[i];
9410 var f = this.findField(fieldError.id);
9412 f.markInvalid(fieldError.msg);
9418 if(typeof errors[id] != 'function' && (field = this.findField(id))){
9419 field.markInvalid(errors[id]);
9423 //Roo.each(this.childForms || [], function (f) {
9424 // f.markInvalid(errors);
9431 * Set values for fields in this form in bulk.
9432 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
9433 * @return {BasicForm} this
9435 setValues : function(values){
9436 if(values instanceof Array){ // array of objects
9437 for(var i = 0, len = values.length; i < len; i++){
9439 var f = this.findField(v.id);
9441 f.setValue(v.value);
9442 if(this.trackResetOnLoad){
9443 f.originalValue = f.getValue();
9447 }else{ // object hash
9450 if(typeof values[id] != 'function' && (field = this.findField(id))){
9452 if (field.setFromData &&
9454 field.displayField &&
9455 // combos' with local stores can
9456 // be queried via setValue()
9457 // to set their value..
9458 (field.store && !field.store.isLocal)
9462 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
9463 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
9464 field.setFromData(sd);
9466 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
9468 field.setFromData(values);
9471 field.setValue(values[id]);
9475 if(this.trackResetOnLoad){
9476 field.originalValue = field.getValue();
9482 //Roo.each(this.childForms || [], function (f) {
9483 // f.setValues(values);
9490 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
9491 * they are returned as an array.
9492 * @param {Boolean} asString
9495 getValues : function(asString){
9496 //if (this.childForms) {
9497 // copy values from the child forms
9498 // Roo.each(this.childForms, function (f) {
9499 // this.setValues(f.getValues());
9505 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
9506 if(asString === true){
9509 return Roo.urlDecode(fs);
9513 * Returns the fields in this form as an object with key/value pairs.
9514 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
9517 getFieldValues : function(with_hidden)
9519 var items = this.getItems();
9521 items.each(function(f){
9527 var v = f.getValue();
9529 if (f.inputType =='radio') {
9530 if (typeof(ret[f.getName()]) == 'undefined') {
9531 ret[f.getName()] = ''; // empty..
9534 if (!f.el.dom.checked) {
9542 if(f.xtype == 'MoneyField'){
9543 ret[f.currencyName] = f.getCurrency();
9546 // not sure if this supported any more..
9547 if ((typeof(v) == 'object') && f.getRawValue) {
9548 v = f.getRawValue() ; // dates..
9550 // combo boxes where name != hiddenName...
9551 if (f.name !== false && f.name != '' && f.name != f.getName()) {
9552 ret[f.name] = f.getRawValue();
9554 ret[f.getName()] = v;
9561 * Clears all invalid messages in this form.
9562 * @return {BasicForm} this
9564 clearInvalid : function(){
9565 var items = this.getItems();
9567 items.each(function(f){
9576 * @return {BasicForm} this
9579 var items = this.getItems();
9580 items.each(function(f){
9584 Roo.each(this.childForms || [], function (f) {
9592 getItems : function()
9594 var r=new Roo.util.MixedCollection(false, function(o){
9595 return o.id || (o.id = Roo.id());
9597 var iter = function(el) {
9604 Roo.each(el.items,function(e) {
9613 hideFields : function(items)
9615 Roo.each(items, function(i){
9617 var f = this.findField(i);
9628 showFields : function(items)
9630 Roo.each(items, function(i){
9632 var f = this.findField(i);
9645 Roo.apply(Roo.bootstrap.Form, {
9672 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
9673 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
9674 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
9675 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
9678 this.maskEl.top.enableDisplayMode("block");
9679 this.maskEl.left.enableDisplayMode("block");
9680 this.maskEl.bottom.enableDisplayMode("block");
9681 this.maskEl.right.enableDisplayMode("block");
9683 this.toolTip = new Roo.bootstrap.Tooltip({
9684 cls : 'roo-form-error-popover',
9686 'left' : ['r-l', [-2,0], 'right'],
9687 'right' : ['l-r', [2,0], 'left'],
9688 'bottom' : ['tl-bl', [0,2], 'top'],
9689 'top' : [ 'bl-tl', [0,-2], 'bottom']
9693 this.toolTip.render(Roo.get(document.body));
9695 this.toolTip.el.enableDisplayMode("block");
9697 Roo.get(document.body).on('click', function(){
9701 Roo.get(document.body).on('touchstart', function(){
9705 this.isApplied = true
9708 mask : function(form, target)
9712 this.target = target;
9714 if(!this.form.errorMask || !target.el){
9718 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
9720 Roo.log(scrollable);
9722 var ot = this.target.el.calcOffsetsTo(scrollable);
9724 var scrollTo = ot[1] - this.form.maskOffset;
9726 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
9728 scrollable.scrollTo('top', scrollTo);
9730 var box = this.target.el.getBox();
9732 var zIndex = Roo.bootstrap.Modal.zIndex++;
9735 this.maskEl.top.setStyle('position', 'absolute');
9736 this.maskEl.top.setStyle('z-index', zIndex);
9737 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
9738 this.maskEl.top.setLeft(0);
9739 this.maskEl.top.setTop(0);
9740 this.maskEl.top.show();
9742 this.maskEl.left.setStyle('position', 'absolute');
9743 this.maskEl.left.setStyle('z-index', zIndex);
9744 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
9745 this.maskEl.left.setLeft(0);
9746 this.maskEl.left.setTop(box.y - this.padding);
9747 this.maskEl.left.show();
9749 this.maskEl.bottom.setStyle('position', 'absolute');
9750 this.maskEl.bottom.setStyle('z-index', zIndex);
9751 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
9752 this.maskEl.bottom.setLeft(0);
9753 this.maskEl.bottom.setTop(box.bottom + this.padding);
9754 this.maskEl.bottom.show();
9756 this.maskEl.right.setStyle('position', 'absolute');
9757 this.maskEl.right.setStyle('z-index', zIndex);
9758 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
9759 this.maskEl.right.setLeft(box.right + this.padding);
9760 this.maskEl.right.setTop(box.y - this.padding);
9761 this.maskEl.right.show();
9763 this.toolTip.bindEl = this.target.el;
9765 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
9767 var tip = this.target.blankText;
9769 if(this.target.getValue() !== '' ) {
9771 if (this.target.invalidText.length) {
9772 tip = this.target.invalidText;
9773 } else if (this.target.regexText.length){
9774 tip = this.target.regexText;
9778 this.toolTip.show(tip);
9780 this.intervalID = window.setInterval(function() {
9781 Roo.bootstrap.Form.popover.unmask();
9784 window.onwheel = function(){ return false;};
9786 (function(){ this.isMasked = true; }).defer(500, this);
9792 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
9796 this.maskEl.top.setStyle('position', 'absolute');
9797 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
9798 this.maskEl.top.hide();
9800 this.maskEl.left.setStyle('position', 'absolute');
9801 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
9802 this.maskEl.left.hide();
9804 this.maskEl.bottom.setStyle('position', 'absolute');
9805 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
9806 this.maskEl.bottom.hide();
9808 this.maskEl.right.setStyle('position', 'absolute');
9809 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
9810 this.maskEl.right.hide();
9812 this.toolTip.hide();
9814 this.toolTip.el.hide();
9816 window.onwheel = function(){ return true;};
9818 if(this.intervalID){
9819 window.clearInterval(this.intervalID);
9820 this.intervalID = false;
9823 this.isMasked = false;
9833 * Ext JS Library 1.1.1
9834 * Copyright(c) 2006-2007, Ext JS, LLC.
9836 * Originally Released Under LGPL - original licence link has changed is not relivant.
9839 * <script type="text/javascript">
9842 * @class Roo.form.VTypes
9843 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
9846 Roo.form.VTypes = function(){
9847 // closure these in so they are only created once.
9848 var alpha = /^[a-zA-Z_]+$/;
9849 var alphanum = /^[a-zA-Z0-9_]+$/;
9850 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
9851 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
9853 // All these messages and functions are configurable
9856 * The function used to validate email addresses
9857 * @param {String} value The email address
9859 'email' : function(v){
9860 return email.test(v);
9863 * The error text to display when the email validation function returns false
9866 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
9868 * The keystroke filter mask to be applied on email input
9871 'emailMask' : /[a-z0-9_\.\-@]/i,
9874 * The function used to validate URLs
9875 * @param {String} value The URL
9877 'url' : function(v){
9881 * The error text to display when the url validation function returns false
9884 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
9887 * The function used to validate alpha values
9888 * @param {String} value The value
9890 'alpha' : function(v){
9891 return alpha.test(v);
9894 * The error text to display when the alpha validation function returns false
9897 'alphaText' : 'This field should only contain letters and _',
9899 * The keystroke filter mask to be applied on alpha input
9902 'alphaMask' : /[a-z_]/i,
9905 * The function used to validate alphanumeric values
9906 * @param {String} value The value
9908 'alphanum' : function(v){
9909 return alphanum.test(v);
9912 * The error text to display when the alphanumeric validation function returns false
9915 'alphanumText' : 'This field should only contain letters, numbers and _',
9917 * The keystroke filter mask to be applied on alphanumeric input
9920 'alphanumMask' : /[a-z0-9_]/i
9930 * @class Roo.bootstrap.Input
9931 * @extends Roo.bootstrap.Component
9932 * Bootstrap Input class
9933 * @cfg {Boolean} disabled is it disabled
9934 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9935 * @cfg {String} name name of the input
9936 * @cfg {string} fieldLabel - the label associated
9937 * @cfg {string} placeholder - placeholder to put in text.
9938 * @cfg {string} before - input group add on before
9939 * @cfg {string} after - input group add on after
9940 * @cfg {string} size - (lg|sm) or leave empty..
9941 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9942 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9943 * @cfg {Number} md colspan out of 12 for computer-sized screens
9944 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9945 * @cfg {string} value default value of the input
9946 * @cfg {Number} labelWidth set the width of label
9947 * @cfg {Number} labellg set the width of label (1-12)
9948 * @cfg {Number} labelmd set the width of label (1-12)
9949 * @cfg {Number} labelsm set the width of label (1-12)
9950 * @cfg {Number} labelxs set the width of label (1-12)
9951 * @cfg {String} labelAlign (top|left)
9952 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9953 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9954 * @cfg {String} indicatorpos (left|right) default left
9955 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9956 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9958 * @cfg {String} align (left|center|right) Default left
9959 * @cfg {Boolean} forceFeedback (true|false) Default false
9962 * Create a new Input
9963 * @param {Object} config The config object
9966 Roo.bootstrap.Input = function(config){
9968 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9973 * Fires when this field receives input focus.
9974 * @param {Roo.form.Field} this
9979 * Fires when this field loses input focus.
9980 * @param {Roo.form.Field} this
9985 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9986 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9987 * @param {Roo.form.Field} this
9988 * @param {Roo.EventObject} e The event object
9993 * Fires just before the field blurs if the field value has changed.
9994 * @param {Roo.form.Field} this
9995 * @param {Mixed} newValue The new value
9996 * @param {Mixed} oldValue The original value
10001 * Fires after the field has been marked as invalid.
10002 * @param {Roo.form.Field} this
10003 * @param {String} msg The validation message
10008 * Fires after the field has been validated with no errors.
10009 * @param {Roo.form.Field} this
10014 * Fires after the key up
10015 * @param {Roo.form.Field} this
10016 * @param {Roo.EventObject} e The event Object
10022 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
10024 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
10025 automatic validation (defaults to "keyup").
10027 validationEvent : "keyup",
10029 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
10031 validateOnBlur : true,
10033 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
10035 validationDelay : 250,
10037 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
10039 focusClass : "x-form-focus", // not needed???
10043 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10045 invalidClass : "has-warning",
10048 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10050 validClass : "has-success",
10053 * @cfg {Boolean} hasFeedback (true|false) default true
10055 hasFeedback : true,
10058 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10060 invalidFeedbackClass : "glyphicon-warning-sign",
10063 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10065 validFeedbackClass : "glyphicon-ok",
10068 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
10070 selectOnFocus : false,
10073 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
10077 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
10082 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
10084 disableKeyFilter : false,
10087 * @cfg {Boolean} disabled True to disable the field (defaults to false).
10091 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
10095 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
10097 blankText : "Please complete this mandatory field",
10100 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
10104 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
10106 maxLength : Number.MAX_VALUE,
10108 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
10110 minLengthText : "The minimum length for this field is {0}",
10112 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
10114 maxLengthText : "The maximum length for this field is {0}",
10118 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
10119 * If available, this function will be called only after the basic validators all return true, and will be passed the
10120 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
10124 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
10125 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
10126 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
10130 * @cfg {String} regexText -- Depricated - use Invalid Text
10135 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
10141 autocomplete: false,
10145 inputType : 'text',
10148 placeholder: false,
10153 preventMark: false,
10154 isFormField : true,
10157 labelAlign : false,
10160 formatedValue : false,
10161 forceFeedback : false,
10163 indicatorpos : 'left',
10173 parentLabelAlign : function()
10176 while (parent.parent()) {
10177 parent = parent.parent();
10178 if (typeof(parent.labelAlign) !='undefined') {
10179 return parent.labelAlign;
10186 getAutoCreate : function()
10188 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10194 if(this.inputType != 'hidden'){
10195 cfg.cls = 'form-group' //input-group
10201 type : this.inputType,
10202 value : this.value,
10203 cls : 'form-control',
10204 placeholder : this.placeholder || '',
10205 autocomplete : this.autocomplete || 'new-password'
10208 if(this.capture.length){
10209 input.capture = this.capture;
10212 if(this.accept.length){
10213 input.accept = this.accept + "/*";
10217 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
10220 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10221 input.maxLength = this.maxLength;
10224 if (this.disabled) {
10225 input.disabled=true;
10228 if (this.readOnly) {
10229 input.readonly=true;
10233 input.name = this.name;
10237 input.cls += ' input-' + this.size;
10241 ['xs','sm','md','lg'].map(function(size){
10242 if (settings[size]) {
10243 cfg.cls += ' col-' + size + '-' + settings[size];
10247 var inputblock = input;
10251 cls: 'glyphicon form-control-feedback'
10254 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10257 cls : 'has-feedback',
10265 if (this.before || this.after) {
10268 cls : 'input-group',
10272 if (this.before && typeof(this.before) == 'string') {
10274 inputblock.cn.push({
10276 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
10280 if (this.before && typeof(this.before) == 'object') {
10281 this.before = Roo.factory(this.before);
10283 inputblock.cn.push({
10285 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
10286 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10290 inputblock.cn.push(input);
10292 if (this.after && typeof(this.after) == 'string') {
10293 inputblock.cn.push({
10295 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
10299 if (this.after && typeof(this.after) == 'object') {
10300 this.after = Roo.factory(this.after);
10302 inputblock.cn.push({
10304 cls : 'roo-input-after input-group-append input-group-text input-group-' +
10305 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10309 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10310 inputblock.cls += ' has-feedback';
10311 inputblock.cn.push(feedback);
10316 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10317 tooltip : 'This field is required'
10319 if (Roo.bootstrap.version == 4) {
10322 style : 'display-none'
10325 if (align ==='left' && this.fieldLabel.length) {
10327 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10334 cls : 'control-label col-form-label',
10335 html : this.fieldLabel
10346 var labelCfg = cfg.cn[1];
10347 var contentCfg = cfg.cn[2];
10349 if(this.indicatorpos == 'right'){
10354 cls : 'control-label col-form-label',
10358 html : this.fieldLabel
10372 labelCfg = cfg.cn[0];
10373 contentCfg = cfg.cn[1];
10377 if(this.labelWidth > 12){
10378 labelCfg.style = "width: " + this.labelWidth + 'px';
10381 if(this.labelWidth < 13 && this.labelmd == 0){
10382 this.labelmd = this.labelWidth;
10385 if(this.labellg > 0){
10386 labelCfg.cls += ' col-lg-' + this.labellg;
10387 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10390 if(this.labelmd > 0){
10391 labelCfg.cls += ' col-md-' + this.labelmd;
10392 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10395 if(this.labelsm > 0){
10396 labelCfg.cls += ' col-sm-' + this.labelsm;
10397 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10400 if(this.labelxs > 0){
10401 labelCfg.cls += ' col-xs-' + this.labelxs;
10402 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10406 } else if ( this.fieldLabel.length) {
10411 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10412 tooltip : 'This field is required'
10416 //cls : 'input-group-addon',
10417 html : this.fieldLabel
10425 if(this.indicatorpos == 'right'){
10430 //cls : 'input-group-addon',
10431 html : this.fieldLabel
10436 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10437 tooltip : 'This field is required'
10457 if (this.parentType === 'Navbar' && this.parent().bar) {
10458 cfg.cls += ' navbar-form';
10461 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
10462 // on BS4 we do this only if not form
10463 cfg.cls += ' navbar-form';
10471 * return the real input element.
10473 inputEl: function ()
10475 return this.el.select('input.form-control',true).first();
10478 tooltipEl : function()
10480 return this.inputEl();
10483 indicatorEl : function()
10485 if (Roo.bootstrap.version == 4) {
10486 return false; // not enabled in v4 yet.
10489 var indicator = this.el.select('i.roo-required-indicator',true).first();
10499 setDisabled : function(v)
10501 var i = this.inputEl().dom;
10503 i.removeAttribute('disabled');
10507 i.setAttribute('disabled','true');
10509 initEvents : function()
10512 this.inputEl().on("keydown" , this.fireKey, this);
10513 this.inputEl().on("focus", this.onFocus, this);
10514 this.inputEl().on("blur", this.onBlur, this);
10516 this.inputEl().relayEvent('keyup', this);
10518 this.indicator = this.indicatorEl();
10520 if(this.indicator){
10521 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
10524 // reference to original value for reset
10525 this.originalValue = this.getValue();
10526 //Roo.form.TextField.superclass.initEvents.call(this);
10527 if(this.validationEvent == 'keyup'){
10528 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
10529 this.inputEl().on('keyup', this.filterValidation, this);
10531 else if(this.validationEvent !== false){
10532 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
10535 if(this.selectOnFocus){
10536 this.on("focus", this.preFocus, this);
10539 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
10540 this.inputEl().on("keypress", this.filterKeys, this);
10542 this.inputEl().relayEvent('keypress', this);
10545 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
10546 this.el.on("click", this.autoSize, this);
10549 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
10550 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
10553 if (typeof(this.before) == 'object') {
10554 this.before.render(this.el.select('.roo-input-before',true).first());
10556 if (typeof(this.after) == 'object') {
10557 this.after.render(this.el.select('.roo-input-after',true).first());
10560 this.inputEl().on('change', this.onChange, this);
10563 filterValidation : function(e){
10564 if(!e.isNavKeyPress()){
10565 this.validationTask.delay(this.validationDelay);
10569 * Validates the field value
10570 * @return {Boolean} True if the value is valid, else false
10572 validate : function(){
10573 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
10574 if(this.disabled || this.validateValue(this.getRawValue())){
10579 this.markInvalid();
10585 * Validates a value according to the field's validation rules and marks the field as invalid
10586 * if the validation fails
10587 * @param {Mixed} value The value to validate
10588 * @return {Boolean} True if the value is valid, else false
10590 validateValue : function(value)
10592 if(this.getVisibilityEl().hasClass('hidden')){
10596 if(value.length < 1) { // if it's blank
10597 if(this.allowBlank){
10603 if(value.length < this.minLength){
10606 if(value.length > this.maxLength){
10610 var vt = Roo.form.VTypes;
10611 if(!vt[this.vtype](value, this)){
10615 if(typeof this.validator == "function"){
10616 var msg = this.validator(value);
10620 if (typeof(msg) == 'string') {
10621 this.invalidText = msg;
10625 if(this.regex && !this.regex.test(value)){
10633 fireKey : function(e){
10634 //Roo.log('field ' + e.getKey());
10635 if(e.isNavKeyPress()){
10636 this.fireEvent("specialkey", this, e);
10639 focus : function (selectText){
10641 this.inputEl().focus();
10642 if(selectText === true){
10643 this.inputEl().dom.select();
10649 onFocus : function(){
10650 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
10651 // this.el.addClass(this.focusClass);
10653 if(!this.hasFocus){
10654 this.hasFocus = true;
10655 this.startValue = this.getValue();
10656 this.fireEvent("focus", this);
10660 beforeBlur : Roo.emptyFn,
10664 onBlur : function(){
10666 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
10667 //this.el.removeClass(this.focusClass);
10669 this.hasFocus = false;
10670 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
10673 var v = this.getValue();
10674 if(String(v) !== String(this.startValue)){
10675 this.fireEvent('change', this, v, this.startValue);
10677 this.fireEvent("blur", this);
10680 onChange : function(e)
10682 var v = this.getValue();
10683 if(String(v) !== String(this.startValue)){
10684 this.fireEvent('change', this, v, this.startValue);
10690 * Resets the current field value to the originally loaded value and clears any validation messages
10692 reset : function(){
10693 this.setValue(this.originalValue);
10697 * Returns the name of the field
10698 * @return {Mixed} name The name field
10700 getName: function(){
10704 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
10705 * @return {Mixed} value The field value
10707 getValue : function(){
10709 var v = this.inputEl().getValue();
10714 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
10715 * @return {Mixed} value The field value
10717 getRawValue : function(){
10718 var v = this.inputEl().getValue();
10724 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
10725 * @param {Mixed} value The value to set
10727 setRawValue : function(v){
10728 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
10731 selectText : function(start, end){
10732 var v = this.getRawValue();
10734 start = start === undefined ? 0 : start;
10735 end = end === undefined ? v.length : end;
10736 var d = this.inputEl().dom;
10737 if(d.setSelectionRange){
10738 d.setSelectionRange(start, end);
10739 }else if(d.createTextRange){
10740 var range = d.createTextRange();
10741 range.moveStart("character", start);
10742 range.moveEnd("character", v.length-end);
10749 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
10750 * @param {Mixed} value The value to set
10752 setValue : function(v){
10755 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
10761 processValue : function(value){
10762 if(this.stripCharsRe){
10763 var newValue = value.replace(this.stripCharsRe, '');
10764 if(newValue !== value){
10765 this.setRawValue(newValue);
10772 preFocus : function(){
10774 if(this.selectOnFocus){
10775 this.inputEl().dom.select();
10778 filterKeys : function(e){
10779 var k = e.getKey();
10780 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
10783 var c = e.getCharCode(), cc = String.fromCharCode(c);
10784 if(Roo.isIE && (e.isSpecialKey() || !cc)){
10787 if(!this.maskRe.test(cc)){
10792 * Clear any invalid styles/messages for this field
10794 clearInvalid : function(){
10796 if(!this.el || this.preventMark){ // not rendered
10801 this.el.removeClass([this.invalidClass, 'is-invalid']);
10803 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10805 var feedback = this.el.select('.form-control-feedback', true).first();
10808 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10813 if(this.indicator){
10814 this.indicator.removeClass('visible');
10815 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10818 this.fireEvent('valid', this);
10822 * Mark this field as valid
10824 markValid : function()
10826 if(!this.el || this.preventMark){ // not rendered...
10830 this.el.removeClass([this.invalidClass, this.validClass]);
10831 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10833 var feedback = this.el.select('.form-control-feedback', true).first();
10836 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10839 if(this.indicator){
10840 this.indicator.removeClass('visible');
10841 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10848 if(this.allowBlank && !this.getRawValue().length){
10851 if (Roo.bootstrap.version == 3) {
10852 this.el.addClass(this.validClass);
10854 this.inputEl().addClass('is-valid');
10857 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10859 var feedback = this.el.select('.form-control-feedback', true).first();
10862 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10863 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10868 this.fireEvent('valid', this);
10872 * Mark this field as invalid
10873 * @param {String} msg The validation message
10875 markInvalid : function(msg)
10877 if(!this.el || this.preventMark){ // not rendered
10881 this.el.removeClass([this.invalidClass, this.validClass]);
10882 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10884 var feedback = this.el.select('.form-control-feedback', true).first();
10887 this.el.select('.form-control-feedback', true).first().removeClass(
10888 [this.invalidFeedbackClass, this.validFeedbackClass]);
10895 if(this.allowBlank && !this.getRawValue().length){
10899 if(this.indicator){
10900 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10901 this.indicator.addClass('visible');
10903 if (Roo.bootstrap.version == 3) {
10904 this.el.addClass(this.invalidClass);
10906 this.inputEl().addClass('is-invalid');
10911 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10913 var feedback = this.el.select('.form-control-feedback', true).first();
10916 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10918 if(this.getValue().length || this.forceFeedback){
10919 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10926 this.fireEvent('invalid', this, msg);
10929 SafariOnKeyDown : function(event)
10931 // this is a workaround for a password hang bug on chrome/ webkit.
10932 if (this.inputEl().dom.type != 'password') {
10936 var isSelectAll = false;
10938 if(this.inputEl().dom.selectionEnd > 0){
10939 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10941 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10942 event.preventDefault();
10947 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10949 event.preventDefault();
10950 // this is very hacky as keydown always get's upper case.
10952 var cc = String.fromCharCode(event.getCharCode());
10953 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10957 adjustWidth : function(tag, w){
10958 tag = tag.toLowerCase();
10959 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10960 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10961 if(tag == 'input'){
10964 if(tag == 'textarea'){
10967 }else if(Roo.isOpera){
10968 if(tag == 'input'){
10971 if(tag == 'textarea'){
10979 setFieldLabel : function(v)
10981 if(!this.rendered){
10985 if(this.indicatorEl()){
10986 var ar = this.el.select('label > span',true);
10988 if (ar.elements.length) {
10989 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10990 this.fieldLabel = v;
10994 var br = this.el.select('label',true);
10996 if(br.elements.length) {
10997 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10998 this.fieldLabel = v;
11002 Roo.log('Cannot Found any of label > span || label in input');
11006 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11007 this.fieldLabel = v;
11022 * @class Roo.bootstrap.TextArea
11023 * @extends Roo.bootstrap.Input
11024 * Bootstrap TextArea class
11025 * @cfg {Number} cols Specifies the visible width of a text area
11026 * @cfg {Number} rows Specifies the visible number of lines in a text area
11027 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
11028 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
11029 * @cfg {string} html text
11032 * Create a new TextArea
11033 * @param {Object} config The config object
11036 Roo.bootstrap.TextArea = function(config){
11037 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
11041 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
11051 getAutoCreate : function(){
11053 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11059 if(this.inputType != 'hidden'){
11060 cfg.cls = 'form-group' //input-group
11068 value : this.value || '',
11069 html: this.html || '',
11070 cls : 'form-control',
11071 placeholder : this.placeholder || ''
11075 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
11076 input.maxLength = this.maxLength;
11080 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
11084 input.cols = this.cols;
11087 if (this.readOnly) {
11088 input.readonly = true;
11092 input.name = this.name;
11096 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
11100 ['xs','sm','md','lg'].map(function(size){
11101 if (settings[size]) {
11102 cfg.cls += ' col-' + size + '-' + settings[size];
11106 var inputblock = input;
11108 if(this.hasFeedback && !this.allowBlank){
11112 cls: 'glyphicon form-control-feedback'
11116 cls : 'has-feedback',
11125 if (this.before || this.after) {
11128 cls : 'input-group',
11132 inputblock.cn.push({
11134 cls : 'input-group-addon',
11139 inputblock.cn.push(input);
11141 if(this.hasFeedback && !this.allowBlank){
11142 inputblock.cls += ' has-feedback';
11143 inputblock.cn.push(feedback);
11147 inputblock.cn.push({
11149 cls : 'input-group-addon',
11156 if (align ==='left' && this.fieldLabel.length) {
11161 cls : 'control-label',
11162 html : this.fieldLabel
11173 if(this.labelWidth > 12){
11174 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
11177 if(this.labelWidth < 13 && this.labelmd == 0){
11178 this.labelmd = this.labelWidth;
11181 if(this.labellg > 0){
11182 cfg.cn[0].cls += ' col-lg-' + this.labellg;
11183 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
11186 if(this.labelmd > 0){
11187 cfg.cn[0].cls += ' col-md-' + this.labelmd;
11188 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
11191 if(this.labelsm > 0){
11192 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
11193 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
11196 if(this.labelxs > 0){
11197 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
11198 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
11201 } else if ( this.fieldLabel.length) {
11206 //cls : 'input-group-addon',
11207 html : this.fieldLabel
11225 if (this.disabled) {
11226 input.disabled=true;
11233 * return the real textarea element.
11235 inputEl: function ()
11237 return this.el.select('textarea.form-control',true).first();
11241 * Clear any invalid styles/messages for this field
11243 clearInvalid : function()
11246 if(!this.el || this.preventMark){ // not rendered
11250 var label = this.el.select('label', true).first();
11251 var icon = this.el.select('i.fa-star', true).first();
11256 this.el.removeClass( this.validClass);
11257 this.inputEl().removeClass('is-invalid');
11259 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11261 var feedback = this.el.select('.form-control-feedback', true).first();
11264 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11269 this.fireEvent('valid', this);
11273 * Mark this field as valid
11275 markValid : function()
11277 if(!this.el || this.preventMark){ // not rendered
11281 this.el.removeClass([this.invalidClass, this.validClass]);
11282 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11284 var feedback = this.el.select('.form-control-feedback', true).first();
11287 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11290 if(this.disabled || this.allowBlank){
11294 var label = this.el.select('label', true).first();
11295 var icon = this.el.select('i.fa-star', true).first();
11300 if (Roo.bootstrap.version == 3) {
11301 this.el.addClass(this.validClass);
11303 this.inputEl().addClass('is-valid');
11307 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11309 var feedback = this.el.select('.form-control-feedback', true).first();
11312 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11313 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11318 this.fireEvent('valid', this);
11322 * Mark this field as invalid
11323 * @param {String} msg The validation message
11325 markInvalid : function(msg)
11327 if(!this.el || this.preventMark){ // not rendered
11331 this.el.removeClass([this.invalidClass, this.validClass]);
11332 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11334 var feedback = this.el.select('.form-control-feedback', true).first();
11337 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11340 if(this.disabled || this.allowBlank){
11344 var label = this.el.select('label', true).first();
11345 var icon = this.el.select('i.fa-star', true).first();
11347 if(!this.getValue().length && label && !icon){
11348 this.el.createChild({
11350 cls : 'text-danger fa fa-lg fa-star',
11351 tooltip : 'This field is required',
11352 style : 'margin-right:5px;'
11356 if (Roo.bootstrap.version == 3) {
11357 this.el.addClass(this.invalidClass);
11359 this.inputEl().addClass('is-invalid');
11362 // fixme ... this may be depricated need to test..
11363 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11365 var feedback = this.el.select('.form-control-feedback', true).first();
11368 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11370 if(this.getValue().length || this.forceFeedback){
11371 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11378 this.fireEvent('invalid', this, msg);
11386 * trigger field - base class for combo..
11391 * @class Roo.bootstrap.TriggerField
11392 * @extends Roo.bootstrap.Input
11393 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
11394 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
11395 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
11396 * for which you can provide a custom implementation. For example:
11398 var trigger = new Roo.bootstrap.TriggerField();
11399 trigger.onTriggerClick = myTriggerFn;
11400 trigger.applyTo('my-field');
11403 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
11404 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
11405 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
11406 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
11407 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
11410 * Create a new TriggerField.
11411 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
11412 * to the base TextField)
11414 Roo.bootstrap.TriggerField = function(config){
11415 this.mimicing = false;
11416 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
11419 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
11421 * @cfg {String} triggerClass A CSS class to apply to the trigger
11424 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
11429 * @cfg {Boolean} removable (true|false) special filter default false
11433 /** @cfg {Boolean} grow @hide */
11434 /** @cfg {Number} growMin @hide */
11435 /** @cfg {Number} growMax @hide */
11441 autoSize: Roo.emptyFn,
11445 deferHeight : true,
11448 actionMode : 'wrap',
11453 getAutoCreate : function(){
11455 var align = this.labelAlign || this.parentLabelAlign();
11460 cls: 'form-group' //input-group
11467 type : this.inputType,
11468 cls : 'form-control',
11469 autocomplete: 'new-password',
11470 placeholder : this.placeholder || ''
11474 input.name = this.name;
11477 input.cls += ' input-' + this.size;
11480 if (this.disabled) {
11481 input.disabled=true;
11484 var inputblock = input;
11486 if(this.hasFeedback && !this.allowBlank){
11490 cls: 'glyphicon form-control-feedback'
11493 if(this.removable && !this.editable && !this.tickable){
11495 cls : 'has-feedback',
11501 cls : 'roo-combo-removable-btn close'
11508 cls : 'has-feedback',
11517 if(this.removable && !this.editable && !this.tickable){
11519 cls : 'roo-removable',
11525 cls : 'roo-combo-removable-btn close'
11532 if (this.before || this.after) {
11535 cls : 'input-group',
11539 inputblock.cn.push({
11541 cls : 'input-group-addon input-group-prepend input-group-text',
11546 inputblock.cn.push(input);
11548 if(this.hasFeedback && !this.allowBlank){
11549 inputblock.cls += ' has-feedback';
11550 inputblock.cn.push(feedback);
11554 inputblock.cn.push({
11556 cls : 'input-group-addon input-group-append input-group-text',
11565 var ibwrap = inputblock;
11570 cls: 'roo-select2-choices',
11574 cls: 'roo-select2-search-field',
11586 cls: 'roo-select2-container input-group',
11591 cls: 'form-hidden-field'
11597 if(!this.multiple && this.showToggleBtn){
11603 if (this.caret != false) {
11606 cls: 'fa fa-' + this.caret
11613 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
11615 Roo.bootstrap.version == 3 ? caret : '',
11618 cls: 'combobox-clear',
11632 combobox.cls += ' roo-select2-container-multi';
11636 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
11637 tooltip : 'This field is required'
11639 if (Roo.bootstrap.version == 4) {
11642 style : 'display:none'
11647 if (align ==='left' && this.fieldLabel.length) {
11649 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
11656 cls : 'control-label',
11657 html : this.fieldLabel
11669 var labelCfg = cfg.cn[1];
11670 var contentCfg = cfg.cn[2];
11672 if(this.indicatorpos == 'right'){
11677 cls : 'control-label',
11681 html : this.fieldLabel
11695 labelCfg = cfg.cn[0];
11696 contentCfg = cfg.cn[1];
11699 if(this.labelWidth > 12){
11700 labelCfg.style = "width: " + this.labelWidth + 'px';
11703 if(this.labelWidth < 13 && this.labelmd == 0){
11704 this.labelmd = this.labelWidth;
11707 if(this.labellg > 0){
11708 labelCfg.cls += ' col-lg-' + this.labellg;
11709 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
11712 if(this.labelmd > 0){
11713 labelCfg.cls += ' col-md-' + this.labelmd;
11714 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
11717 if(this.labelsm > 0){
11718 labelCfg.cls += ' col-sm-' + this.labelsm;
11719 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
11722 if(this.labelxs > 0){
11723 labelCfg.cls += ' col-xs-' + this.labelxs;
11724 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
11727 } else if ( this.fieldLabel.length) {
11728 // Roo.log(" label");
11733 //cls : 'input-group-addon',
11734 html : this.fieldLabel
11742 if(this.indicatorpos == 'right'){
11750 html : this.fieldLabel
11764 // Roo.log(" no label && no align");
11771 ['xs','sm','md','lg'].map(function(size){
11772 if (settings[size]) {
11773 cfg.cls += ' col-' + size + '-' + settings[size];
11784 onResize : function(w, h){
11785 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
11786 // if(typeof w == 'number'){
11787 // var x = w - this.trigger.getWidth();
11788 // this.inputEl().setWidth(this.adjustWidth('input', x));
11789 // this.trigger.setStyle('left', x+'px');
11794 adjustSize : Roo.BoxComponent.prototype.adjustSize,
11797 getResizeEl : function(){
11798 return this.inputEl();
11802 getPositionEl : function(){
11803 return this.inputEl();
11807 alignErrorIcon : function(){
11808 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
11812 initEvents : function(){
11816 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
11817 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
11818 if(!this.multiple && this.showToggleBtn){
11819 this.trigger = this.el.select('span.dropdown-toggle',true).first();
11820 if(this.hideTrigger){
11821 this.trigger.setDisplayed(false);
11823 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
11827 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
11830 if(this.removable && !this.editable && !this.tickable){
11831 var close = this.closeTriggerEl();
11834 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
11835 close.on('click', this.removeBtnClick, this, close);
11839 //this.trigger.addClassOnOver('x-form-trigger-over');
11840 //this.trigger.addClassOnClick('x-form-trigger-click');
11843 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
11847 closeTriggerEl : function()
11849 var close = this.el.select('.roo-combo-removable-btn', true).first();
11850 return close ? close : false;
11853 removeBtnClick : function(e, h, el)
11855 e.preventDefault();
11857 if(this.fireEvent("remove", this) !== false){
11859 this.fireEvent("afterremove", this)
11863 createList : function()
11865 this.list = Roo.get(document.body).createChild({
11866 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
11867 cls: 'typeahead typeahead-long dropdown-menu',
11868 style: 'display:none'
11871 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
11876 initTrigger : function(){
11881 onDestroy : function(){
11883 this.trigger.removeAllListeners();
11884 // this.trigger.remove();
11887 // this.wrap.remove();
11889 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
11893 onFocus : function(){
11894 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
11896 if(!this.mimicing){
11897 this.wrap.addClass('x-trigger-wrap-focus');
11898 this.mimicing = true;
11899 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
11900 if(this.monitorTab){
11901 this.el.on("keydown", this.checkTab, this);
11908 checkTab : function(e){
11909 if(e.getKey() == e.TAB){
11910 this.triggerBlur();
11915 onBlur : function(){
11920 mimicBlur : function(e, t){
11922 if(!this.wrap.contains(t) && this.validateBlur()){
11923 this.triggerBlur();
11929 triggerBlur : function(){
11930 this.mimicing = false;
11931 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
11932 if(this.monitorTab){
11933 this.el.un("keydown", this.checkTab, this);
11935 //this.wrap.removeClass('x-trigger-wrap-focus');
11936 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11940 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11941 validateBlur : function(e, t){
11946 onDisable : function(){
11947 this.inputEl().dom.disabled = true;
11948 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11950 // this.wrap.addClass('x-item-disabled');
11955 onEnable : function(){
11956 this.inputEl().dom.disabled = false;
11957 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11959 // this.el.removeClass('x-item-disabled');
11964 onShow : function(){
11965 var ae = this.getActionEl();
11968 ae.dom.style.display = '';
11969 ae.dom.style.visibility = 'visible';
11975 onHide : function(){
11976 var ae = this.getActionEl();
11977 ae.dom.style.display = 'none';
11981 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11982 * by an implementing function.
11984 * @param {EventObject} e
11986 onTriggerClick : Roo.emptyFn
11990 * Ext JS Library 1.1.1
11991 * Copyright(c) 2006-2007, Ext JS, LLC.
11993 * Originally Released Under LGPL - original licence link has changed is not relivant.
11996 * <script type="text/javascript">
12001 * @class Roo.data.SortTypes
12003 * Defines the default sorting (casting?) comparison functions used when sorting data.
12005 Roo.data.SortTypes = {
12007 * Default sort that does nothing
12008 * @param {Mixed} s The value being converted
12009 * @return {Mixed} The comparison value
12011 none : function(s){
12016 * The regular expression used to strip tags
12020 stripTagsRE : /<\/?[^>]+>/gi,
12023 * Strips all HTML tags to sort on text only
12024 * @param {Mixed} s The value being converted
12025 * @return {String} The comparison value
12027 asText : function(s){
12028 return String(s).replace(this.stripTagsRE, "");
12032 * Strips all HTML tags to sort on text only - Case insensitive
12033 * @param {Mixed} s The value being converted
12034 * @return {String} The comparison value
12036 asUCText : function(s){
12037 return String(s).toUpperCase().replace(this.stripTagsRE, "");
12041 * Case insensitive string
12042 * @param {Mixed} s The value being converted
12043 * @return {String} The comparison value
12045 asUCString : function(s) {
12046 return String(s).toUpperCase();
12051 * @param {Mixed} s The value being converted
12052 * @return {Number} The comparison value
12054 asDate : function(s) {
12058 if(s instanceof Date){
12059 return s.getTime();
12061 return Date.parse(String(s));
12066 * @param {Mixed} s The value being converted
12067 * @return {Float} The comparison value
12069 asFloat : function(s) {
12070 var val = parseFloat(String(s).replace(/,/g, ""));
12079 * @param {Mixed} s The value being converted
12080 * @return {Number} The comparison value
12082 asInt : function(s) {
12083 var val = parseInt(String(s).replace(/,/g, ""));
12091 * Ext JS Library 1.1.1
12092 * Copyright(c) 2006-2007, Ext JS, LLC.
12094 * Originally Released Under LGPL - original licence link has changed is not relivant.
12097 * <script type="text/javascript">
12101 * @class Roo.data.Record
12102 * Instances of this class encapsulate both record <em>definition</em> information, and record
12103 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
12104 * to access Records cached in an {@link Roo.data.Store} object.<br>
12106 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
12107 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
12110 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
12112 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
12113 * {@link #create}. The parameters are the same.
12114 * @param {Array} data An associative Array of data values keyed by the field name.
12115 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
12116 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
12117 * not specified an integer id is generated.
12119 Roo.data.Record = function(data, id){
12120 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
12125 * Generate a constructor for a specific record layout.
12126 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
12127 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
12128 * Each field definition object may contain the following properties: <ul>
12129 * <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,
12130 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
12131 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
12132 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
12133 * is being used, then this is a string containing the javascript expression to reference the data relative to
12134 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
12135 * to the data item relative to the record element. If the mapping expression is the same as the field name,
12136 * this may be omitted.</p></li>
12137 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
12138 * <ul><li>auto (Default, implies no conversion)</li>
12143 * <li>date</li></ul></p></li>
12144 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
12145 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
12146 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
12147 * by the Reader into an object that will be stored in the Record. It is passed the
12148 * following parameters:<ul>
12149 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
12151 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
12153 * <br>usage:<br><pre><code>
12154 var TopicRecord = Roo.data.Record.create(
12155 {name: 'title', mapping: 'topic_title'},
12156 {name: 'author', mapping: 'username'},
12157 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
12158 {name: 'lastPost', mapping: 'post_time', type: 'date'},
12159 {name: 'lastPoster', mapping: 'user2'},
12160 {name: 'excerpt', mapping: 'post_text'}
12163 var myNewRecord = new TopicRecord({
12164 title: 'Do my job please',
12167 lastPost: new Date(),
12168 lastPoster: 'Animal',
12169 excerpt: 'No way dude!'
12171 myStore.add(myNewRecord);
12176 Roo.data.Record.create = function(o){
12177 var f = function(){
12178 f.superclass.constructor.apply(this, arguments);
12180 Roo.extend(f, Roo.data.Record);
12181 var p = f.prototype;
12182 p.fields = new Roo.util.MixedCollection(false, function(field){
12185 for(var i = 0, len = o.length; i < len; i++){
12186 p.fields.add(new Roo.data.Field(o[i]));
12188 f.getField = function(name){
12189 return p.fields.get(name);
12194 Roo.data.Record.AUTO_ID = 1000;
12195 Roo.data.Record.EDIT = 'edit';
12196 Roo.data.Record.REJECT = 'reject';
12197 Roo.data.Record.COMMIT = 'commit';
12199 Roo.data.Record.prototype = {
12201 * Readonly flag - true if this record has been modified.
12210 join : function(store){
12211 this.store = store;
12215 * Set the named field to the specified value.
12216 * @param {String} name The name of the field to set.
12217 * @param {Object} value The value to set the field to.
12219 set : function(name, value){
12220 if(this.data[name] == value){
12224 if(!this.modified){
12225 this.modified = {};
12227 if(typeof this.modified[name] == 'undefined'){
12228 this.modified[name] = this.data[name];
12230 this.data[name] = value;
12231 if(!this.editing && this.store){
12232 this.store.afterEdit(this);
12237 * Get the value of the named field.
12238 * @param {String} name The name of the field to get the value of.
12239 * @return {Object} The value of the field.
12241 get : function(name){
12242 return this.data[name];
12246 beginEdit : function(){
12247 this.editing = true;
12248 this.modified = {};
12252 cancelEdit : function(){
12253 this.editing = false;
12254 delete this.modified;
12258 endEdit : function(){
12259 this.editing = false;
12260 if(this.dirty && this.store){
12261 this.store.afterEdit(this);
12266 * Usually called by the {@link Roo.data.Store} which owns the Record.
12267 * Rejects all changes made to the Record since either creation, or the last commit operation.
12268 * Modified fields are reverted to their original values.
12270 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12271 * of reject operations.
12273 reject : function(){
12274 var m = this.modified;
12276 if(typeof m[n] != "function"){
12277 this.data[n] = m[n];
12280 this.dirty = false;
12281 delete this.modified;
12282 this.editing = false;
12284 this.store.afterReject(this);
12289 * Usually called by the {@link Roo.data.Store} which owns the Record.
12290 * Commits all changes made to the Record since either creation, or the last commit operation.
12292 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12293 * of commit operations.
12295 commit : function(){
12296 this.dirty = false;
12297 delete this.modified;
12298 this.editing = false;
12300 this.store.afterCommit(this);
12305 hasError : function(){
12306 return this.error != null;
12310 clearError : function(){
12315 * Creates a copy of this record.
12316 * @param {String} id (optional) A new record id if you don't want to use this record's id
12319 copy : function(newId) {
12320 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
12324 * Ext JS Library 1.1.1
12325 * Copyright(c) 2006-2007, Ext JS, LLC.
12327 * Originally Released Under LGPL - original licence link has changed is not relivant.
12330 * <script type="text/javascript">
12336 * @class Roo.data.Store
12337 * @extends Roo.util.Observable
12338 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
12339 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
12341 * 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
12342 * has no knowledge of the format of the data returned by the Proxy.<br>
12344 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
12345 * instances from the data object. These records are cached and made available through accessor functions.
12347 * Creates a new Store.
12348 * @param {Object} config A config object containing the objects needed for the Store to access data,
12349 * and read the data into Records.
12351 Roo.data.Store = function(config){
12352 this.data = new Roo.util.MixedCollection(false);
12353 this.data.getKey = function(o){
12356 this.baseParams = {};
12358 this.paramNames = {
12363 "multisort" : "_multisort"
12366 if(config && config.data){
12367 this.inlineData = config.data;
12368 delete config.data;
12371 Roo.apply(this, config);
12373 if(this.reader){ // reader passed
12374 this.reader = Roo.factory(this.reader, Roo.data);
12375 this.reader.xmodule = this.xmodule || false;
12376 if(!this.recordType){
12377 this.recordType = this.reader.recordType;
12379 if(this.reader.onMetaChange){
12380 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
12384 if(this.recordType){
12385 this.fields = this.recordType.prototype.fields;
12387 this.modified = [];
12391 * @event datachanged
12392 * Fires when the data cache has changed, and a widget which is using this Store
12393 * as a Record cache should refresh its view.
12394 * @param {Store} this
12396 datachanged : true,
12398 * @event metachange
12399 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
12400 * @param {Store} this
12401 * @param {Object} meta The JSON metadata
12406 * Fires when Records have been added to the Store
12407 * @param {Store} this
12408 * @param {Roo.data.Record[]} records The array of Records added
12409 * @param {Number} index The index at which the record(s) were added
12414 * Fires when a Record has been removed from the Store
12415 * @param {Store} this
12416 * @param {Roo.data.Record} record The Record that was removed
12417 * @param {Number} index The index at which the record was removed
12422 * Fires when a Record has been updated
12423 * @param {Store} this
12424 * @param {Roo.data.Record} record The Record that was updated
12425 * @param {String} operation The update operation being performed. Value may be one of:
12427 Roo.data.Record.EDIT
12428 Roo.data.Record.REJECT
12429 Roo.data.Record.COMMIT
12435 * Fires when the data cache has been cleared.
12436 * @param {Store} this
12440 * @event beforeload
12441 * Fires before a request is made for a new data object. If the beforeload handler returns false
12442 * the load action will be canceled.
12443 * @param {Store} this
12444 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12448 * @event beforeloadadd
12449 * Fires after a new set of Records has been loaded.
12450 * @param {Store} this
12451 * @param {Roo.data.Record[]} records The Records that were loaded
12452 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12454 beforeloadadd : true,
12457 * Fires after a new set of Records has been loaded, before they are added to the store.
12458 * @param {Store} this
12459 * @param {Roo.data.Record[]} records The Records that were loaded
12460 * @param {Object} options The loading options that were specified (see {@link #load} for details)
12461 * @params {Object} return from reader
12465 * @event loadexception
12466 * Fires if an exception occurs in the Proxy during loading.
12467 * Called with the signature of the Proxy's "loadexception" event.
12468 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
12471 * @param {Object} return from JsonData.reader() - success, totalRecords, records
12472 * @param {Object} load options
12473 * @param {Object} jsonData from your request (normally this contains the Exception)
12475 loadexception : true
12479 this.proxy = Roo.factory(this.proxy, Roo.data);
12480 this.proxy.xmodule = this.xmodule || false;
12481 this.relayEvents(this.proxy, ["loadexception"]);
12483 this.sortToggle = {};
12484 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
12486 Roo.data.Store.superclass.constructor.call(this);
12488 if(this.inlineData){
12489 this.loadData(this.inlineData);
12490 delete this.inlineData;
12494 Roo.extend(Roo.data.Store, Roo.util.Observable, {
12496 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
12497 * without a remote query - used by combo/forms at present.
12501 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
12504 * @cfg {Array} data Inline data to be loaded when the store is initialized.
12507 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
12508 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
12511 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
12512 * on any HTTP request
12515 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
12518 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
12522 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
12523 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
12525 remoteSort : false,
12528 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
12529 * loaded or when a record is removed. (defaults to false).
12531 pruneModifiedRecords : false,
12534 lastOptions : null,
12537 * Add Records to the Store and fires the add event.
12538 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
12540 add : function(records){
12541 records = [].concat(records);
12542 for(var i = 0, len = records.length; i < len; i++){
12543 records[i].join(this);
12545 var index = this.data.length;
12546 this.data.addAll(records);
12547 this.fireEvent("add", this, records, index);
12551 * Remove a Record from the Store and fires the remove event.
12552 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
12554 remove : function(record){
12555 var index = this.data.indexOf(record);
12556 this.data.removeAt(index);
12558 if(this.pruneModifiedRecords){
12559 this.modified.remove(record);
12561 this.fireEvent("remove", this, record, index);
12565 * Remove all Records from the Store and fires the clear event.
12567 removeAll : function(){
12569 if(this.pruneModifiedRecords){
12570 this.modified = [];
12572 this.fireEvent("clear", this);
12576 * Inserts Records to the Store at the given index and fires the add event.
12577 * @param {Number} index The start index at which to insert the passed Records.
12578 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
12580 insert : function(index, records){
12581 records = [].concat(records);
12582 for(var i = 0, len = records.length; i < len; i++){
12583 this.data.insert(index, records[i]);
12584 records[i].join(this);
12586 this.fireEvent("add", this, records, index);
12590 * Get the index within the cache of the passed Record.
12591 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
12592 * @return {Number} The index of the passed Record. Returns -1 if not found.
12594 indexOf : function(record){
12595 return this.data.indexOf(record);
12599 * Get the index within the cache of the Record with the passed id.
12600 * @param {String} id The id of the Record to find.
12601 * @return {Number} The index of the Record. Returns -1 if not found.
12603 indexOfId : function(id){
12604 return this.data.indexOfKey(id);
12608 * Get the Record with the specified id.
12609 * @param {String} id The id of the Record to find.
12610 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
12612 getById : function(id){
12613 return this.data.key(id);
12617 * Get the Record at the specified index.
12618 * @param {Number} index The index of the Record to find.
12619 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
12621 getAt : function(index){
12622 return this.data.itemAt(index);
12626 * Returns a range of Records between specified indices.
12627 * @param {Number} startIndex (optional) The starting index (defaults to 0)
12628 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
12629 * @return {Roo.data.Record[]} An array of Records
12631 getRange : function(start, end){
12632 return this.data.getRange(start, end);
12636 storeOptions : function(o){
12637 o = Roo.apply({}, o);
12640 this.lastOptions = o;
12644 * Loads the Record cache from the configured Proxy using the configured Reader.
12646 * If using remote paging, then the first load call must specify the <em>start</em>
12647 * and <em>limit</em> properties in the options.params property to establish the initial
12648 * position within the dataset, and the number of Records to cache on each read from the Proxy.
12650 * <strong>It is important to note that for remote data sources, loading is asynchronous,
12651 * and this call will return before the new data has been loaded. Perform any post-processing
12652 * in a callback function, or in a "load" event handler.</strong>
12654 * @param {Object} options An object containing properties which control loading options:<ul>
12655 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
12656 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
12657 * passed the following arguments:<ul>
12658 * <li>r : Roo.data.Record[]</li>
12659 * <li>options: Options object from the load call</li>
12660 * <li>success: Boolean success indicator</li></ul></li>
12661 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
12662 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
12665 load : function(options){
12666 options = options || {};
12667 if(this.fireEvent("beforeload", this, options) !== false){
12668 this.storeOptions(options);
12669 var p = Roo.apply(options.params || {}, this.baseParams);
12670 // if meta was not loaded from remote source.. try requesting it.
12671 if (!this.reader.metaFromRemote) {
12672 p._requestMeta = 1;
12674 if(this.sortInfo && this.remoteSort){
12675 var pn = this.paramNames;
12676 p[pn["sort"]] = this.sortInfo.field;
12677 p[pn["dir"]] = this.sortInfo.direction;
12679 if (this.multiSort) {
12680 var pn = this.paramNames;
12681 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
12684 this.proxy.load(p, this.reader, this.loadRecords, this, options);
12689 * Reloads the Record cache from the configured Proxy using the configured Reader and
12690 * the options from the last load operation performed.
12691 * @param {Object} options (optional) An object containing properties which may override the options
12692 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
12693 * the most recently used options are reused).
12695 reload : function(options){
12696 this.load(Roo.applyIf(options||{}, this.lastOptions));
12700 // Called as a callback by the Reader during a load operation.
12701 loadRecords : function(o, options, success){
12702 if(!o || success === false){
12703 if(success !== false){
12704 this.fireEvent("load", this, [], options, o);
12706 if(options.callback){
12707 options.callback.call(options.scope || this, [], options, false);
12711 // if data returned failure - throw an exception.
12712 if (o.success === false) {
12713 // show a message if no listener is registered.
12714 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
12715 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
12717 // loadmask wil be hooked into this..
12718 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
12721 var r = o.records, t = o.totalRecords || r.length;
12723 this.fireEvent("beforeloadadd", this, r, options, o);
12725 if(!options || options.add !== true){
12726 if(this.pruneModifiedRecords){
12727 this.modified = [];
12729 for(var i = 0, len = r.length; i < len; i++){
12733 this.data = this.snapshot;
12734 delete this.snapshot;
12737 this.data.addAll(r);
12738 this.totalLength = t;
12740 this.fireEvent("datachanged", this);
12742 this.totalLength = Math.max(t, this.data.length+r.length);
12746 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
12748 var e = new Roo.data.Record({});
12750 e.set(this.parent.displayField, this.parent.emptyTitle);
12751 e.set(this.parent.valueField, '');
12756 this.fireEvent("load", this, r, options, o);
12757 if(options.callback){
12758 options.callback.call(options.scope || this, r, options, true);
12764 * Loads data from a passed data block. A Reader which understands the format of the data
12765 * must have been configured in the constructor.
12766 * @param {Object} data The data block from which to read the Records. The format of the data expected
12767 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
12768 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
12770 loadData : function(o, append){
12771 var r = this.reader.readRecords(o);
12772 this.loadRecords(r, {add: append}, true);
12776 * using 'cn' the nested child reader read the child array into it's child stores.
12777 * @param {Object} rec The record with a 'children array
12779 loadDataFromChildren : function(rec)
12781 this.loadData(this.reader.toLoadData(rec));
12786 * Gets the number of cached records.
12788 * <em>If using paging, this may not be the total size of the dataset. If the data object
12789 * used by the Reader contains the dataset size, then the getTotalCount() function returns
12790 * the data set size</em>
12792 getCount : function(){
12793 return this.data.length || 0;
12797 * Gets the total number of records in the dataset as returned by the server.
12799 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
12800 * the dataset size</em>
12802 getTotalCount : function(){
12803 return this.totalLength || 0;
12807 * Returns the sort state of the Store as an object with two properties:
12809 field {String} The name of the field by which the Records are sorted
12810 direction {String} The sort order, "ASC" or "DESC"
12813 getSortState : function(){
12814 return this.sortInfo;
12818 applySort : function(){
12819 if(this.sortInfo && !this.remoteSort){
12820 var s = this.sortInfo, f = s.field;
12821 var st = this.fields.get(f).sortType;
12822 var fn = function(r1, r2){
12823 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
12824 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
12826 this.data.sort(s.direction, fn);
12827 if(this.snapshot && this.snapshot != this.data){
12828 this.snapshot.sort(s.direction, fn);
12834 * Sets the default sort column and order to be used by the next load operation.
12835 * @param {String} fieldName The name of the field to sort by.
12836 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
12838 setDefaultSort : function(field, dir){
12839 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
12843 * Sort the Records.
12844 * If remote sorting is used, the sort is performed on the server, and the cache is
12845 * reloaded. If local sorting is used, the cache is sorted internally.
12846 * @param {String} fieldName The name of the field to sort by.
12847 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
12849 sort : function(fieldName, dir){
12850 var f = this.fields.get(fieldName);
12852 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
12854 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
12855 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
12860 this.sortToggle[f.name] = dir;
12861 this.sortInfo = {field: f.name, direction: dir};
12862 if(!this.remoteSort){
12864 this.fireEvent("datachanged", this);
12866 this.load(this.lastOptions);
12871 * Calls the specified function for each of the Records in the cache.
12872 * @param {Function} fn The function to call. The Record is passed as the first parameter.
12873 * Returning <em>false</em> aborts and exits the iteration.
12874 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
12876 each : function(fn, scope){
12877 this.data.each(fn, scope);
12881 * Gets all records modified since the last commit. Modified records are persisted across load operations
12882 * (e.g., during paging).
12883 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
12885 getModifiedRecords : function(){
12886 return this.modified;
12890 createFilterFn : function(property, value, anyMatch){
12891 if(!value.exec){ // not a regex
12892 value = String(value);
12893 if(value.length == 0){
12896 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
12898 return function(r){
12899 return value.test(r.data[property]);
12904 * Sums the value of <i>property</i> for each record between start and end and returns the result.
12905 * @param {String} property A field on your records
12906 * @param {Number} start The record index to start at (defaults to 0)
12907 * @param {Number} end The last record index to include (defaults to length - 1)
12908 * @return {Number} The sum
12910 sum : function(property, start, end){
12911 var rs = this.data.items, v = 0;
12912 start = start || 0;
12913 end = (end || end === 0) ? end : rs.length-1;
12915 for(var i = start; i <= end; i++){
12916 v += (rs[i].data[property] || 0);
12922 * Filter the records by a specified property.
12923 * @param {String} field A field on your records
12924 * @param {String/RegExp} value Either a string that the field
12925 * should start with or a RegExp to test against the field
12926 * @param {Boolean} anyMatch True to match any part not just the beginning
12928 filter : function(property, value, anyMatch){
12929 var fn = this.createFilterFn(property, value, anyMatch);
12930 return fn ? this.filterBy(fn) : this.clearFilter();
12934 * Filter by a function. The specified function will be called with each
12935 * record in this data source. If the function returns true the record is included,
12936 * otherwise it is filtered.
12937 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12938 * @param {Object} scope (optional) The scope of the function (defaults to this)
12940 filterBy : function(fn, scope){
12941 this.snapshot = this.snapshot || this.data;
12942 this.data = this.queryBy(fn, scope||this);
12943 this.fireEvent("datachanged", this);
12947 * Query the records by a specified property.
12948 * @param {String} field A field on your records
12949 * @param {String/RegExp} value Either a string that the field
12950 * should start with or a RegExp to test against the field
12951 * @param {Boolean} anyMatch True to match any part not just the beginning
12952 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12954 query : function(property, value, anyMatch){
12955 var fn = this.createFilterFn(property, value, anyMatch);
12956 return fn ? this.queryBy(fn) : this.data.clone();
12960 * Query by a function. The specified function will be called with each
12961 * record in this data source. If the function returns true the record is included
12963 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12964 * @param {Object} scope (optional) The scope of the function (defaults to this)
12965 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12967 queryBy : function(fn, scope){
12968 var data = this.snapshot || this.data;
12969 return data.filterBy(fn, scope||this);
12973 * Collects unique values for a particular dataIndex from this store.
12974 * @param {String} dataIndex The property to collect
12975 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12976 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12977 * @return {Array} An array of the unique values
12979 collect : function(dataIndex, allowNull, bypassFilter){
12980 var d = (bypassFilter === true && this.snapshot) ?
12981 this.snapshot.items : this.data.items;
12982 var v, sv, r = [], l = {};
12983 for(var i = 0, len = d.length; i < len; i++){
12984 v = d[i].data[dataIndex];
12986 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12995 * Revert to a view of the Record cache with no filtering applied.
12996 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12998 clearFilter : function(suppressEvent){
12999 if(this.snapshot && this.snapshot != this.data){
13000 this.data = this.snapshot;
13001 delete this.snapshot;
13002 if(suppressEvent !== true){
13003 this.fireEvent("datachanged", this);
13009 afterEdit : function(record){
13010 if(this.modified.indexOf(record) == -1){
13011 this.modified.push(record);
13013 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
13017 afterReject : function(record){
13018 this.modified.remove(record);
13019 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
13023 afterCommit : function(record){
13024 this.modified.remove(record);
13025 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
13029 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
13030 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
13032 commitChanges : function(){
13033 var m = this.modified.slice(0);
13034 this.modified = [];
13035 for(var i = 0, len = m.length; i < len; i++){
13041 * Cancel outstanding changes on all changed records.
13043 rejectChanges : function(){
13044 var m = this.modified.slice(0);
13045 this.modified = [];
13046 for(var i = 0, len = m.length; i < len; i++){
13051 onMetaChange : function(meta, rtype, o){
13052 this.recordType = rtype;
13053 this.fields = rtype.prototype.fields;
13054 delete this.snapshot;
13055 this.sortInfo = meta.sortInfo || this.sortInfo;
13056 this.modified = [];
13057 this.fireEvent('metachange', this, this.reader.meta);
13060 moveIndex : function(data, type)
13062 var index = this.indexOf(data);
13064 var newIndex = index + type;
13068 this.insert(newIndex, data);
13073 * Ext JS Library 1.1.1
13074 * Copyright(c) 2006-2007, Ext JS, LLC.
13076 * Originally Released Under LGPL - original licence link has changed is not relivant.
13079 * <script type="text/javascript">
13083 * @class Roo.data.SimpleStore
13084 * @extends Roo.data.Store
13085 * Small helper class to make creating Stores from Array data easier.
13086 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
13087 * @cfg {Array} fields An array of field definition objects, or field name strings.
13088 * @cfg {Object} an existing reader (eg. copied from another store)
13089 * @cfg {Array} data The multi-dimensional array of data
13091 * @param {Object} config
13093 Roo.data.SimpleStore = function(config)
13095 Roo.data.SimpleStore.superclass.constructor.call(this, {
13097 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
13100 Roo.data.Record.create(config.fields)
13102 proxy : new Roo.data.MemoryProxy(config.data)
13106 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
13108 * Ext JS Library 1.1.1
13109 * Copyright(c) 2006-2007, Ext JS, LLC.
13111 * Originally Released Under LGPL - original licence link has changed is not relivant.
13114 * <script type="text/javascript">
13119 * @extends Roo.data.Store
13120 * @class Roo.data.JsonStore
13121 * Small helper class to make creating Stores for JSON data easier. <br/>
13123 var store = new Roo.data.JsonStore({
13124 url: 'get-images.php',
13126 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
13129 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
13130 * JsonReader and HttpProxy (unless inline data is provided).</b>
13131 * @cfg {Array} fields An array of field definition objects, or field name strings.
13133 * @param {Object} config
13135 Roo.data.JsonStore = function(c){
13136 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
13137 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
13138 reader: new Roo.data.JsonReader(c, c.fields)
13141 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
13143 * Ext JS Library 1.1.1
13144 * Copyright(c) 2006-2007, Ext JS, LLC.
13146 * Originally Released Under LGPL - original licence link has changed is not relivant.
13149 * <script type="text/javascript">
13153 Roo.data.Field = function(config){
13154 if(typeof config == "string"){
13155 config = {name: config};
13157 Roo.apply(this, config);
13160 this.type = "auto";
13163 var st = Roo.data.SortTypes;
13164 // named sortTypes are supported, here we look them up
13165 if(typeof this.sortType == "string"){
13166 this.sortType = st[this.sortType];
13169 // set default sortType for strings and dates
13170 if(!this.sortType){
13173 this.sortType = st.asUCString;
13176 this.sortType = st.asDate;
13179 this.sortType = st.none;
13184 var stripRe = /[\$,%]/g;
13186 // prebuilt conversion function for this field, instead of
13187 // switching every time we're reading a value
13189 var cv, dateFormat = this.dateFormat;
13194 cv = function(v){ return v; };
13197 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
13201 return v !== undefined && v !== null && v !== '' ?
13202 parseInt(String(v).replace(stripRe, ""), 10) : '';
13207 return v !== undefined && v !== null && v !== '' ?
13208 parseFloat(String(v).replace(stripRe, ""), 10) : '';
13213 cv = function(v){ return v === true || v === "true" || v == 1; };
13220 if(v instanceof Date){
13224 if(dateFormat == "timestamp"){
13225 return new Date(v*1000);
13227 return Date.parseDate(v, dateFormat);
13229 var parsed = Date.parse(v);
13230 return parsed ? new Date(parsed) : null;
13239 Roo.data.Field.prototype = {
13247 * Ext JS Library 1.1.1
13248 * Copyright(c) 2006-2007, Ext JS, LLC.
13250 * Originally Released Under LGPL - original licence link has changed is not relivant.
13253 * <script type="text/javascript">
13256 // Base class for reading structured data from a data source. This class is intended to be
13257 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
13260 * @class Roo.data.DataReader
13261 * Base class for reading structured data from a data source. This class is intended to be
13262 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
13265 Roo.data.DataReader = function(meta, recordType){
13269 this.recordType = recordType instanceof Array ?
13270 Roo.data.Record.create(recordType) : recordType;
13273 Roo.data.DataReader.prototype = {
13276 readerType : 'Data',
13278 * Create an empty record
13279 * @param {Object} data (optional) - overlay some values
13280 * @return {Roo.data.Record} record created.
13282 newRow : function(d) {
13284 this.recordType.prototype.fields.each(function(c) {
13286 case 'int' : da[c.name] = 0; break;
13287 case 'date' : da[c.name] = new Date(); break;
13288 case 'float' : da[c.name] = 0.0; break;
13289 case 'boolean' : da[c.name] = false; break;
13290 default : da[c.name] = ""; break;
13294 return new this.recordType(Roo.apply(da, d));
13300 * Ext JS Library 1.1.1
13301 * Copyright(c) 2006-2007, Ext JS, LLC.
13303 * Originally Released Under LGPL - original licence link has changed is not relivant.
13306 * <script type="text/javascript">
13310 * @class Roo.data.DataProxy
13311 * @extends Roo.data.Observable
13312 * This class is an abstract base class for implementations which provide retrieval of
13313 * unformatted data objects.<br>
13315 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
13316 * (of the appropriate type which knows how to parse the data object) to provide a block of
13317 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
13319 * Custom implementations must implement the load method as described in
13320 * {@link Roo.data.HttpProxy#load}.
13322 Roo.data.DataProxy = function(){
13325 * @event beforeload
13326 * Fires before a network request is made to retrieve a data object.
13327 * @param {Object} This DataProxy object.
13328 * @param {Object} params The params parameter to the load function.
13333 * Fires before the load method's callback is called.
13334 * @param {Object} This DataProxy object.
13335 * @param {Object} o The data object.
13336 * @param {Object} arg The callback argument object passed to the load function.
13340 * @event loadexception
13341 * Fires if an Exception occurs during data retrieval.
13342 * @param {Object} This DataProxy object.
13343 * @param {Object} o The data object.
13344 * @param {Object} arg The callback argument object passed to the load function.
13345 * @param {Object} e The Exception.
13347 loadexception : true
13349 Roo.data.DataProxy.superclass.constructor.call(this);
13352 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
13355 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
13359 * Ext JS Library 1.1.1
13360 * Copyright(c) 2006-2007, Ext JS, LLC.
13362 * Originally Released Under LGPL - original licence link has changed is not relivant.
13365 * <script type="text/javascript">
13368 * @class Roo.data.MemoryProxy
13369 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
13370 * to the Reader when its load method is called.
13372 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
13374 Roo.data.MemoryProxy = function(data){
13378 Roo.data.MemoryProxy.superclass.constructor.call(this);
13382 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
13385 * Load data from the requested source (in this case an in-memory
13386 * data object passed to the constructor), read the data object into
13387 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
13388 * process that block using the passed callback.
13389 * @param {Object} params This parameter is not used by the MemoryProxy class.
13390 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13391 * object into a block of Roo.data.Records.
13392 * @param {Function} callback The function into which to pass the block of Roo.data.records.
13393 * The function must be passed <ul>
13394 * <li>The Record block object</li>
13395 * <li>The "arg" argument from the load function</li>
13396 * <li>A boolean success indicator</li>
13398 * @param {Object} scope The scope in which to call the callback
13399 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13401 load : function(params, reader, callback, scope, arg){
13402 params = params || {};
13405 result = reader.readRecords(params.data ? params.data :this.data);
13407 this.fireEvent("loadexception", this, arg, null, e);
13408 callback.call(scope, null, arg, false);
13411 callback.call(scope, result, arg, true);
13415 update : function(params, records){
13420 * Ext JS Library 1.1.1
13421 * Copyright(c) 2006-2007, Ext JS, LLC.
13423 * Originally Released Under LGPL - original licence link has changed is not relivant.
13426 * <script type="text/javascript">
13429 * @class Roo.data.HttpProxy
13430 * @extends Roo.data.DataProxy
13431 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
13432 * configured to reference a certain URL.<br><br>
13434 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
13435 * from which the running page was served.<br><br>
13437 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
13439 * Be aware that to enable the browser to parse an XML document, the server must set
13440 * the Content-Type header in the HTTP response to "text/xml".
13442 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
13443 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
13444 * will be used to make the request.
13446 Roo.data.HttpProxy = function(conn){
13447 Roo.data.HttpProxy.superclass.constructor.call(this);
13448 // is conn a conn config or a real conn?
13450 this.useAjax = !conn || !conn.events;
13454 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
13455 // thse are take from connection...
13458 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
13461 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
13462 * extra parameters to each request made by this object. (defaults to undefined)
13465 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
13466 * to each request made by this object. (defaults to undefined)
13469 * @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)
13472 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13475 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
13481 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13485 * Return the {@link Roo.data.Connection} object being used by this Proxy.
13486 * @return {Connection} The Connection object. This object may be used to subscribe to events on
13487 * a finer-grained basis than the DataProxy events.
13489 getConnection : function(){
13490 return this.useAjax ? Roo.Ajax : this.conn;
13494 * Load data from the configured {@link Roo.data.Connection}, read the data object into
13495 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
13496 * process that block using the passed callback.
13497 * @param {Object} params An object containing properties which are to be used as HTTP parameters
13498 * for the request to the remote server.
13499 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13500 * object into a block of Roo.data.Records.
13501 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
13502 * The function must be passed <ul>
13503 * <li>The Record block object</li>
13504 * <li>The "arg" argument from the load function</li>
13505 * <li>A boolean success indicator</li>
13507 * @param {Object} scope The scope in which to call the callback
13508 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13510 load : function(params, reader, callback, scope, arg){
13511 if(this.fireEvent("beforeload", this, params) !== false){
13513 params : params || {},
13515 callback : callback,
13520 callback : this.loadResponse,
13524 Roo.applyIf(o, this.conn);
13525 if(this.activeRequest){
13526 Roo.Ajax.abort(this.activeRequest);
13528 this.activeRequest = Roo.Ajax.request(o);
13530 this.conn.request(o);
13533 callback.call(scope||this, null, arg, false);
13538 loadResponse : function(o, success, response){
13539 delete this.activeRequest;
13541 this.fireEvent("loadexception", this, o, response);
13542 o.request.callback.call(o.request.scope, null, o.request.arg, false);
13547 result = o.reader.read(response);
13549 this.fireEvent("loadexception", this, o, response, e);
13550 o.request.callback.call(o.request.scope, null, o.request.arg, false);
13554 this.fireEvent("load", this, o, o.request.arg);
13555 o.request.callback.call(o.request.scope, result, o.request.arg, true);
13559 update : function(dataSet){
13564 updateResponse : function(dataSet){
13569 * Ext JS Library 1.1.1
13570 * Copyright(c) 2006-2007, Ext JS, LLC.
13572 * Originally Released Under LGPL - original licence link has changed is not relivant.
13575 * <script type="text/javascript">
13579 * @class Roo.data.ScriptTagProxy
13580 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
13581 * other than the originating domain of the running page.<br><br>
13583 * <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
13584 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
13586 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
13587 * source code that is used as the source inside a <script> tag.<br><br>
13589 * In order for the browser to process the returned data, the server must wrap the data object
13590 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
13591 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
13592 * depending on whether the callback name was passed:
13595 boolean scriptTag = false;
13596 String cb = request.getParameter("callback");
13599 response.setContentType("text/javascript");
13601 response.setContentType("application/x-json");
13603 Writer out = response.getWriter();
13605 out.write(cb + "(");
13607 out.print(dataBlock.toJsonString());
13614 * @param {Object} config A configuration object.
13616 Roo.data.ScriptTagProxy = function(config){
13617 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
13618 Roo.apply(this, config);
13619 this.head = document.getElementsByTagName("head")[0];
13622 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
13624 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
13626 * @cfg {String} url The URL from which to request the data object.
13629 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
13633 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
13634 * the server the name of the callback function set up by the load call to process the returned data object.
13635 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
13636 * javascript output which calls this named function passing the data object as its only parameter.
13638 callbackParam : "callback",
13640 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
13641 * name to the request.
13646 * Load data from the configured URL, read the data object into
13647 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
13648 * process that block using the passed callback.
13649 * @param {Object} params An object containing properties which are to be used as HTTP parameters
13650 * for the request to the remote server.
13651 * @param {Roo.data.DataReader} reader The Reader object which converts the data
13652 * object into a block of Roo.data.Records.
13653 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
13654 * The function must be passed <ul>
13655 * <li>The Record block object</li>
13656 * <li>The "arg" argument from the load function</li>
13657 * <li>A boolean success indicator</li>
13659 * @param {Object} scope The scope in which to call the callback
13660 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
13662 load : function(params, reader, callback, scope, arg){
13663 if(this.fireEvent("beforeload", this, params) !== false){
13665 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
13667 var url = this.url;
13668 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
13670 url += "&_dc=" + (new Date().getTime());
13672 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
13675 cb : "stcCallback"+transId,
13676 scriptId : "stcScript"+transId,
13680 callback : callback,
13686 window[trans.cb] = function(o){
13687 conn.handleResponse(o, trans);
13690 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
13692 if(this.autoAbort !== false){
13696 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
13698 var script = document.createElement("script");
13699 script.setAttribute("src", url);
13700 script.setAttribute("type", "text/javascript");
13701 script.setAttribute("id", trans.scriptId);
13702 this.head.appendChild(script);
13704 this.trans = trans;
13706 callback.call(scope||this, null, arg, false);
13711 isLoading : function(){
13712 return this.trans ? true : false;
13716 * Abort the current server request.
13718 abort : function(){
13719 if(this.isLoading()){
13720 this.destroyTrans(this.trans);
13725 destroyTrans : function(trans, isLoaded){
13726 this.head.removeChild(document.getElementById(trans.scriptId));
13727 clearTimeout(trans.timeoutId);
13729 window[trans.cb] = undefined;
13731 delete window[trans.cb];
13734 // if hasn't been loaded, wait for load to remove it to prevent script error
13735 window[trans.cb] = function(){
13736 window[trans.cb] = undefined;
13738 delete window[trans.cb];
13745 handleResponse : function(o, trans){
13746 this.trans = false;
13747 this.destroyTrans(trans, true);
13750 result = trans.reader.readRecords(o);
13752 this.fireEvent("loadexception", this, o, trans.arg, e);
13753 trans.callback.call(trans.scope||window, null, trans.arg, false);
13756 this.fireEvent("load", this, o, trans.arg);
13757 trans.callback.call(trans.scope||window, result, trans.arg, true);
13761 handleFailure : function(trans){
13762 this.trans = false;
13763 this.destroyTrans(trans, false);
13764 this.fireEvent("loadexception", this, null, trans.arg);
13765 trans.callback.call(trans.scope||window, null, trans.arg, false);
13769 * Ext JS Library 1.1.1
13770 * Copyright(c) 2006-2007, Ext JS, LLC.
13772 * Originally Released Under LGPL - original licence link has changed is not relivant.
13775 * <script type="text/javascript">
13779 * @class Roo.data.JsonReader
13780 * @extends Roo.data.DataReader
13781 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
13782 * based on mappings in a provided Roo.data.Record constructor.
13784 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
13785 * in the reply previously.
13790 var RecordDef = Roo.data.Record.create([
13791 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
13792 {name: 'occupation'} // This field will use "occupation" as the mapping.
13794 var myReader = new Roo.data.JsonReader({
13795 totalProperty: "results", // The property which contains the total dataset size (optional)
13796 root: "rows", // The property which contains an Array of row objects
13797 id: "id" // The property within each row object that provides an ID for the record (optional)
13801 * This would consume a JSON file like this:
13803 { 'results': 2, 'rows': [
13804 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
13805 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
13808 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
13809 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
13810 * paged from the remote server.
13811 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
13812 * @cfg {String} root name of the property which contains the Array of row objects.
13813 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13814 * @cfg {Array} fields Array of field definition objects
13816 * Create a new JsonReader
13817 * @param {Object} meta Metadata configuration options
13818 * @param {Object} recordType Either an Array of field definition objects,
13819 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
13821 Roo.data.JsonReader = function(meta, recordType){
13824 // set some defaults:
13825 Roo.applyIf(meta, {
13826 totalProperty: 'total',
13827 successProperty : 'success',
13832 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13834 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
13836 readerType : 'Json',
13839 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
13840 * Used by Store query builder to append _requestMeta to params.
13843 metaFromRemote : false,
13845 * This method is only used by a DataProxy which has retrieved data from a remote server.
13846 * @param {Object} response The XHR object which contains the JSON data in its responseText.
13847 * @return {Object} data A data block which is used by an Roo.data.Store object as
13848 * a cache of Roo.data.Records.
13850 read : function(response){
13851 var json = response.responseText;
13853 var o = /* eval:var:o */ eval("("+json+")");
13855 throw {message: "JsonReader.read: Json object not found"};
13861 this.metaFromRemote = true;
13862 this.meta = o.metaData;
13863 this.recordType = Roo.data.Record.create(o.metaData.fields);
13864 this.onMetaChange(this.meta, this.recordType, o);
13866 return this.readRecords(o);
13869 // private function a store will implement
13870 onMetaChange : function(meta, recordType, o){
13877 simpleAccess: function(obj, subsc) {
13884 getJsonAccessor: function(){
13886 return function(expr) {
13888 return(re.test(expr))
13889 ? new Function("obj", "return obj." + expr)
13894 return Roo.emptyFn;
13899 * Create a data block containing Roo.data.Records from an XML document.
13900 * @param {Object} o An object which contains an Array of row objects in the property specified
13901 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
13902 * which contains the total size of the dataset.
13903 * @return {Object} data A data block which is used by an Roo.data.Store object as
13904 * a cache of Roo.data.Records.
13906 readRecords : function(o){
13908 * After any data loads, the raw JSON data is available for further custom processing.
13912 var s = this.meta, Record = this.recordType,
13913 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
13915 // Generate extraction functions for the totalProperty, the root, the id, and for each field
13917 if(s.totalProperty) {
13918 this.getTotal = this.getJsonAccessor(s.totalProperty);
13920 if(s.successProperty) {
13921 this.getSuccess = this.getJsonAccessor(s.successProperty);
13923 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
13925 var g = this.getJsonAccessor(s.id);
13926 this.getId = function(rec) {
13928 return (r === undefined || r === "") ? null : r;
13931 this.getId = function(){return null;};
13934 for(var jj = 0; jj < fl; jj++){
13936 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
13937 this.ef[jj] = this.getJsonAccessor(map);
13941 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
13942 if(s.totalProperty){
13943 var vt = parseInt(this.getTotal(o), 10);
13948 if(s.successProperty){
13949 var vs = this.getSuccess(o);
13950 if(vs === false || vs === 'false'){
13955 for(var i = 0; i < c; i++){
13958 var id = this.getId(n);
13959 for(var j = 0; j < fl; j++){
13961 var v = this.ef[j](n);
13963 Roo.log('missing convert for ' + f.name);
13967 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13969 var record = new Record(values, id);
13971 records[i] = record;
13977 totalRecords : totalRecords
13980 // used when loading children.. @see loadDataFromChildren
13981 toLoadData: function(rec)
13983 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
13984 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
13985 return { data : data, total : data.length };
13990 * Ext JS Library 1.1.1
13991 * Copyright(c) 2006-2007, Ext JS, LLC.
13993 * Originally Released Under LGPL - original licence link has changed is not relivant.
13996 * <script type="text/javascript">
14000 * @class Roo.data.ArrayReader
14001 * @extends Roo.data.DataReader
14002 * Data reader class to create an Array of Roo.data.Record objects from an Array.
14003 * Each element of that Array represents a row of data fields. The
14004 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
14005 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
14009 var RecordDef = Roo.data.Record.create([
14010 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
14011 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
14013 var myReader = new Roo.data.ArrayReader({
14014 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
14018 * This would consume an Array like this:
14020 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
14024 * Create a new JsonReader
14025 * @param {Object} meta Metadata configuration options.
14026 * @param {Object|Array} recordType Either an Array of field definition objects
14028 * @cfg {Array} fields Array of field definition objects
14029 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14030 * as specified to {@link Roo.data.Record#create},
14031 * or an {@link Roo.data.Record} object
14034 * created using {@link Roo.data.Record#create}.
14036 Roo.data.ArrayReader = function(meta, recordType)
14038 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14041 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
14044 * Create a data block containing Roo.data.Records from an XML document.
14045 * @param {Object} o An Array of row objects which represents the dataset.
14046 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
14047 * a cache of Roo.data.Records.
14049 readRecords : function(o)
14051 var sid = this.meta ? this.meta.id : null;
14052 var recordType = this.recordType, fields = recordType.prototype.fields;
14055 for(var i = 0; i < root.length; i++){
14058 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
14059 for(var j = 0, jlen = fields.length; j < jlen; j++){
14060 var f = fields.items[j];
14061 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
14062 var v = n[k] !== undefined ? n[k] : f.defaultValue;
14064 values[f.name] = v;
14066 var record = new recordType(values, id);
14068 records[records.length] = record;
14072 totalRecords : records.length
14075 // used when loading children.. @see loadDataFromChildren
14076 toLoadData: function(rec)
14078 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14079 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14090 * @class Roo.bootstrap.ComboBox
14091 * @extends Roo.bootstrap.TriggerField
14092 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
14093 * @cfg {Boolean} append (true|false) default false
14094 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
14095 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
14096 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
14097 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
14098 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
14099 * @cfg {Boolean} animate default true
14100 * @cfg {Boolean} emptyResultText only for touch device
14101 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
14102 * @cfg {String} emptyTitle default ''
14104 * Create a new ComboBox.
14105 * @param {Object} config Configuration options
14107 Roo.bootstrap.ComboBox = function(config){
14108 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
14112 * Fires when the dropdown list is expanded
14113 * @param {Roo.bootstrap.ComboBox} combo This combo box
14118 * Fires when the dropdown list is collapsed
14119 * @param {Roo.bootstrap.ComboBox} combo This combo box
14123 * @event beforeselect
14124 * Fires before a list item is selected. Return false to cancel the selection.
14125 * @param {Roo.bootstrap.ComboBox} combo This combo box
14126 * @param {Roo.data.Record} record The data record returned from the underlying store
14127 * @param {Number} index The index of the selected item in the dropdown list
14129 'beforeselect' : true,
14132 * Fires when a list item is selected
14133 * @param {Roo.bootstrap.ComboBox} combo This combo box
14134 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
14135 * @param {Number} index The index of the selected item in the dropdown list
14139 * @event beforequery
14140 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
14141 * The event object passed has these properties:
14142 * @param {Roo.bootstrap.ComboBox} combo This combo box
14143 * @param {String} query The query
14144 * @param {Boolean} forceAll true to force "all" query
14145 * @param {Boolean} cancel true to cancel the query
14146 * @param {Object} e The query event object
14148 'beforequery': true,
14151 * Fires when the 'add' icon is pressed (add a listener to enable add button)
14152 * @param {Roo.bootstrap.ComboBox} combo This combo box
14157 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
14158 * @param {Roo.bootstrap.ComboBox} combo This combo box
14159 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
14164 * Fires when the remove value from the combobox array
14165 * @param {Roo.bootstrap.ComboBox} combo This combo box
14169 * @event afterremove
14170 * Fires when the remove value from the combobox array
14171 * @param {Roo.bootstrap.ComboBox} combo This combo box
14173 'afterremove' : true,
14175 * @event specialfilter
14176 * Fires when specialfilter
14177 * @param {Roo.bootstrap.ComboBox} combo This combo box
14179 'specialfilter' : true,
14182 * Fires when tick the element
14183 * @param {Roo.bootstrap.ComboBox} combo This combo box
14187 * @event touchviewdisplay
14188 * Fires when touch view require special display (default is using displayField)
14189 * @param {Roo.bootstrap.ComboBox} combo This combo box
14190 * @param {Object} cfg set html .
14192 'touchviewdisplay' : true
14197 this.tickItems = [];
14199 this.selectedIndex = -1;
14200 if(this.mode == 'local'){
14201 if(config.queryDelay === undefined){
14202 this.queryDelay = 10;
14204 if(config.minChars === undefined){
14210 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
14213 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
14214 * rendering into an Roo.Editor, defaults to false)
14217 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
14218 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
14221 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
14224 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
14225 * the dropdown list (defaults to undefined, with no header element)
14229 * @cfg {String/Roo.Template} tpl The template to use to render the output
14233 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
14235 listWidth: undefined,
14237 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
14238 * mode = 'remote' or 'text' if mode = 'local')
14240 displayField: undefined,
14243 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
14244 * mode = 'remote' or 'value' if mode = 'local').
14245 * Note: use of a valueField requires the user make a selection
14246 * in order for a value to be mapped.
14248 valueField: undefined,
14250 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
14255 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
14256 * field's data value (defaults to the underlying DOM element's name)
14258 hiddenName: undefined,
14260 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
14264 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
14266 selectedClass: 'active',
14269 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14273 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
14274 * anchor positions (defaults to 'tl-bl')
14276 listAlign: 'tl-bl?',
14278 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
14282 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
14283 * query specified by the allQuery config option (defaults to 'query')
14285 triggerAction: 'query',
14287 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
14288 * (defaults to 4, does not apply if editable = false)
14292 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
14293 * delay (typeAheadDelay) if it matches a known value (defaults to false)
14297 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
14298 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
14302 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
14303 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
14307 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
14308 * when editable = true (defaults to false)
14310 selectOnFocus:false,
14312 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
14314 queryParam: 'query',
14316 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
14317 * when mode = 'remote' (defaults to 'Loading...')
14319 loadingText: 'Loading...',
14321 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
14325 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
14329 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
14330 * traditional select (defaults to true)
14334 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
14338 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
14342 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
14343 * listWidth has a higher value)
14347 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
14348 * allow the user to set arbitrary text into the field (defaults to false)
14350 forceSelection:false,
14352 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
14353 * if typeAhead = true (defaults to 250)
14355 typeAheadDelay : 250,
14357 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
14358 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
14360 valueNotFoundText : undefined,
14362 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
14364 blockFocus : false,
14367 * @cfg {Boolean} disableClear Disable showing of clear button.
14369 disableClear : false,
14371 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
14373 alwaysQuery : false,
14376 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
14381 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
14383 invalidClass : "has-warning",
14386 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
14388 validClass : "has-success",
14391 * @cfg {Boolean} specialFilter (true|false) special filter default false
14393 specialFilter : false,
14396 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
14398 mobileTouchView : true,
14401 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
14403 useNativeIOS : false,
14406 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
14408 mobile_restrict_height : false,
14410 ios_options : false,
14422 btnPosition : 'right',
14423 triggerList : true,
14424 showToggleBtn : true,
14426 emptyResultText: 'Empty',
14427 triggerText : 'Select',
14430 // element that contains real text value.. (when hidden is used..)
14432 getAutoCreate : function()
14437 * Render classic select for iso
14440 if(Roo.isIOS && this.useNativeIOS){
14441 cfg = this.getAutoCreateNativeIOS();
14449 if(Roo.isTouch && this.mobileTouchView){
14450 cfg = this.getAutoCreateTouchView();
14457 if(!this.tickable){
14458 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
14463 * ComboBox with tickable selections
14466 var align = this.labelAlign || this.parentLabelAlign();
14469 cls : 'form-group roo-combobox-tickable' //input-group
14472 var btn_text_select = '';
14473 var btn_text_done = '';
14474 var btn_text_cancel = '';
14476 if (this.btn_text_show) {
14477 btn_text_select = 'Select';
14478 btn_text_done = 'Done';
14479 btn_text_cancel = 'Cancel';
14484 cls : 'tickable-buttons',
14489 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
14490 //html : this.triggerText
14491 html: btn_text_select
14497 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
14499 html: btn_text_done
14505 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
14507 html: btn_text_cancel
14513 buttons.cn.unshift({
14515 cls: 'roo-select2-search-field-input'
14521 Roo.each(buttons.cn, function(c){
14523 c.cls += ' btn-' + _this.size;
14526 if (_this.disabled) {
14533 style : 'display: contents',
14538 cls: 'form-hidden-field'
14542 cls: 'roo-select2-choices',
14546 cls: 'roo-select2-search-field',
14557 cls: 'roo-select2-container input-group roo-select2-container-multi',
14563 // cls: 'typeahead typeahead-long dropdown-menu',
14564 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
14569 if(this.hasFeedback && !this.allowBlank){
14573 cls: 'glyphicon form-control-feedback'
14576 combobox.cn.push(feedback);
14581 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
14582 tooltip : 'This field is required'
14584 if (Roo.bootstrap.version == 4) {
14587 style : 'display:none'
14590 if (align ==='left' && this.fieldLabel.length) {
14592 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
14599 cls : 'control-label col-form-label',
14600 html : this.fieldLabel
14612 var labelCfg = cfg.cn[1];
14613 var contentCfg = cfg.cn[2];
14616 if(this.indicatorpos == 'right'){
14622 cls : 'control-label col-form-label',
14626 html : this.fieldLabel
14642 labelCfg = cfg.cn[0];
14643 contentCfg = cfg.cn[1];
14647 if(this.labelWidth > 12){
14648 labelCfg.style = "width: " + this.labelWidth + 'px';
14651 if(this.labelWidth < 13 && this.labelmd == 0){
14652 this.labelmd = this.labelWidth;
14655 if(this.labellg > 0){
14656 labelCfg.cls += ' col-lg-' + this.labellg;
14657 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14660 if(this.labelmd > 0){
14661 labelCfg.cls += ' col-md-' + this.labelmd;
14662 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14665 if(this.labelsm > 0){
14666 labelCfg.cls += ' col-sm-' + this.labelsm;
14667 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14670 if(this.labelxs > 0){
14671 labelCfg.cls += ' col-xs-' + this.labelxs;
14672 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14676 } else if ( this.fieldLabel.length) {
14677 // Roo.log(" label");
14682 //cls : 'input-group-addon',
14683 html : this.fieldLabel
14688 if(this.indicatorpos == 'right'){
14692 //cls : 'input-group-addon',
14693 html : this.fieldLabel
14703 // Roo.log(" no label && no align");
14710 ['xs','sm','md','lg'].map(function(size){
14711 if (settings[size]) {
14712 cfg.cls += ' col-' + size + '-' + settings[size];
14720 _initEventsCalled : false,
14723 initEvents: function()
14725 if (this._initEventsCalled) { // as we call render... prevent looping...
14728 this._initEventsCalled = true;
14731 throw "can not find store for combo";
14734 this.indicator = this.indicatorEl();
14736 this.store = Roo.factory(this.store, Roo.data);
14737 this.store.parent = this;
14739 // if we are building from html. then this element is so complex, that we can not really
14740 // use the rendered HTML.
14741 // so we have to trash and replace the previous code.
14742 if (Roo.XComponent.build_from_html) {
14743 // remove this element....
14744 var e = this.el.dom, k=0;
14745 while (e ) { e = e.previousSibling; ++k;}
14750 this.rendered = false;
14752 this.render(this.parent().getChildContainer(true), k);
14755 if(Roo.isIOS && this.useNativeIOS){
14756 this.initIOSView();
14764 if(Roo.isTouch && this.mobileTouchView){
14765 this.initTouchView();
14770 this.initTickableEvents();
14774 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
14776 if(this.hiddenName){
14778 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14780 this.hiddenField.dom.value =
14781 this.hiddenValue !== undefined ? this.hiddenValue :
14782 this.value !== undefined ? this.value : '';
14784 // prevent input submission
14785 this.el.dom.removeAttribute('name');
14786 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14791 // this.el.dom.setAttribute('autocomplete', 'off');
14794 var cls = 'x-combo-list';
14796 //this.list = new Roo.Layer({
14797 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
14803 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14804 _this.list.setWidth(lw);
14807 this.list.on('mouseover', this.onViewOver, this);
14808 this.list.on('mousemove', this.onViewMove, this);
14809 this.list.on('scroll', this.onViewScroll, this);
14812 this.list.swallowEvent('mousewheel');
14813 this.assetHeight = 0;
14816 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
14817 this.assetHeight += this.header.getHeight();
14820 this.innerList = this.list.createChild({cls:cls+'-inner'});
14821 this.innerList.on('mouseover', this.onViewOver, this);
14822 this.innerList.on('mousemove', this.onViewMove, this);
14823 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14825 if(this.allowBlank && !this.pageSize && !this.disableClear){
14826 this.footer = this.list.createChild({cls:cls+'-ft'});
14827 this.pageTb = new Roo.Toolbar(this.footer);
14831 this.footer = this.list.createChild({cls:cls+'-ft'});
14832 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
14833 {pageSize: this.pageSize});
14837 if (this.pageTb && this.allowBlank && !this.disableClear) {
14839 this.pageTb.add(new Roo.Toolbar.Fill(), {
14840 cls: 'x-btn-icon x-btn-clear',
14842 handler: function()
14845 _this.clearValue();
14846 _this.onSelect(false, -1);
14851 this.assetHeight += this.footer.getHeight();
14856 this.tpl = Roo.bootstrap.version == 4 ?
14857 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
14858 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
14861 this.view = new Roo.View(this.list, this.tpl, {
14862 singleSelect:true, store: this.store, selectedClass: this.selectedClass
14864 //this.view.wrapEl.setDisplayed(false);
14865 this.view.on('click', this.onViewClick, this);
14868 this.store.on('beforeload', this.onBeforeLoad, this);
14869 this.store.on('load', this.onLoad, this);
14870 this.store.on('loadexception', this.onLoadException, this);
14872 if(this.resizable){
14873 this.resizer = new Roo.Resizable(this.list, {
14874 pinned:true, handles:'se'
14876 this.resizer.on('resize', function(r, w, h){
14877 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
14878 this.listWidth = w;
14879 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
14880 this.restrictHeight();
14882 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
14885 if(!this.editable){
14886 this.editable = true;
14887 this.setEditable(false);
14892 if (typeof(this.events.add.listeners) != 'undefined') {
14894 this.addicon = this.wrap.createChild(
14895 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
14897 this.addicon.on('click', function(e) {
14898 this.fireEvent('add', this);
14901 if (typeof(this.events.edit.listeners) != 'undefined') {
14903 this.editicon = this.wrap.createChild(
14904 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
14905 if (this.addicon) {
14906 this.editicon.setStyle('margin-left', '40px');
14908 this.editicon.on('click', function(e) {
14910 // we fire even if inothing is selected..
14911 this.fireEvent('edit', this, this.lastData );
14917 this.keyNav = new Roo.KeyNav(this.inputEl(), {
14918 "up" : function(e){
14919 this.inKeyMode = true;
14923 "down" : function(e){
14924 if(!this.isExpanded()){
14925 this.onTriggerClick();
14927 this.inKeyMode = true;
14932 "enter" : function(e){
14933 // this.onViewClick();
14937 if(this.fireEvent("specialkey", this, e)){
14938 this.onViewClick(false);
14944 "esc" : function(e){
14948 "tab" : function(e){
14951 if(this.fireEvent("specialkey", this, e)){
14952 this.onViewClick(false);
14960 doRelay : function(foo, bar, hname){
14961 if(hname == 'down' || this.scope.isExpanded()){
14962 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14971 this.queryDelay = Math.max(this.queryDelay || 10,
14972 this.mode == 'local' ? 10 : 250);
14975 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14977 if(this.typeAhead){
14978 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14980 if(this.editable !== false){
14981 this.inputEl().on("keyup", this.onKeyUp, this);
14983 if(this.forceSelection){
14984 this.inputEl().on('blur', this.doForce, this);
14988 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14989 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14993 initTickableEvents: function()
14997 if(this.hiddenName){
14999 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15001 this.hiddenField.dom.value =
15002 this.hiddenValue !== undefined ? this.hiddenValue :
15003 this.value !== undefined ? this.value : '';
15005 // prevent input submission
15006 this.el.dom.removeAttribute('name');
15007 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15012 // this.list = this.el.select('ul.dropdown-menu',true).first();
15014 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15015 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15016 if(this.triggerList){
15017 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
15020 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
15021 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
15023 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
15024 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
15026 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
15027 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
15029 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
15030 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
15031 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
15034 this.cancelBtn.hide();
15039 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15040 _this.list.setWidth(lw);
15043 this.list.on('mouseover', this.onViewOver, this);
15044 this.list.on('mousemove', this.onViewMove, this);
15046 this.list.on('scroll', this.onViewScroll, this);
15049 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
15050 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
15053 this.view = new Roo.View(this.list, this.tpl, {
15058 selectedClass: this.selectedClass
15061 //this.view.wrapEl.setDisplayed(false);
15062 this.view.on('click', this.onViewClick, this);
15066 this.store.on('beforeload', this.onBeforeLoad, this);
15067 this.store.on('load', this.onLoad, this);
15068 this.store.on('loadexception', this.onLoadException, this);
15071 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
15072 "up" : function(e){
15073 this.inKeyMode = true;
15077 "down" : function(e){
15078 this.inKeyMode = true;
15082 "enter" : function(e){
15083 if(this.fireEvent("specialkey", this, e)){
15084 this.onViewClick(false);
15090 "esc" : function(e){
15091 this.onTickableFooterButtonClick(e, false, false);
15094 "tab" : function(e){
15095 this.fireEvent("specialkey", this, e);
15097 this.onTickableFooterButtonClick(e, false, false);
15104 doRelay : function(e, fn, key){
15105 if(this.scope.isExpanded()){
15106 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15115 this.queryDelay = Math.max(this.queryDelay || 10,
15116 this.mode == 'local' ? 10 : 250);
15119 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15121 if(this.typeAhead){
15122 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15125 if(this.editable !== false){
15126 this.tickableInputEl().on("keyup", this.onKeyUp, this);
15129 this.indicator = this.indicatorEl();
15131 if(this.indicator){
15132 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
15133 this.indicator.hide();
15138 onDestroy : function(){
15140 this.view.setStore(null);
15141 this.view.el.removeAllListeners();
15142 this.view.el.remove();
15143 this.view.purgeListeners();
15146 this.list.dom.innerHTML = '';
15150 this.store.un('beforeload', this.onBeforeLoad, this);
15151 this.store.un('load', this.onLoad, this);
15152 this.store.un('loadexception', this.onLoadException, this);
15154 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
15158 fireKey : function(e){
15159 if(e.isNavKeyPress() && !this.list.isVisible()){
15160 this.fireEvent("specialkey", this, e);
15165 onResize: function(w, h){
15166 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
15168 // if(typeof w != 'number'){
15169 // // we do not handle it!?!?
15172 // var tw = this.trigger.getWidth();
15173 // // tw += this.addicon ? this.addicon.getWidth() : 0;
15174 // // tw += this.editicon ? this.editicon.getWidth() : 0;
15176 // this.inputEl().setWidth( this.adjustWidth('input', x));
15178 // //this.trigger.setStyle('left', x+'px');
15180 // if(this.list && this.listWidth === undefined){
15181 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
15182 // this.list.setWidth(lw);
15183 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15191 * Allow or prevent the user from directly editing the field text. If false is passed,
15192 * the user will only be able to select from the items defined in the dropdown list. This method
15193 * is the runtime equivalent of setting the 'editable' config option at config time.
15194 * @param {Boolean} value True to allow the user to directly edit the field text
15196 setEditable : function(value){
15197 if(value == this.editable){
15200 this.editable = value;
15202 this.inputEl().dom.setAttribute('readOnly', true);
15203 this.inputEl().on('mousedown', this.onTriggerClick, this);
15204 this.inputEl().addClass('x-combo-noedit');
15206 this.inputEl().dom.setAttribute('readOnly', false);
15207 this.inputEl().un('mousedown', this.onTriggerClick, this);
15208 this.inputEl().removeClass('x-combo-noedit');
15214 onBeforeLoad : function(combo,opts){
15215 if(!this.hasFocus){
15219 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
15221 this.restrictHeight();
15222 this.selectedIndex = -1;
15226 onLoad : function(){
15228 this.hasQuery = false;
15230 if(!this.hasFocus){
15234 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15235 this.loading.hide();
15238 if(this.store.getCount() > 0){
15241 this.restrictHeight();
15242 if(this.lastQuery == this.allQuery){
15243 if(this.editable && !this.tickable){
15244 this.inputEl().dom.select();
15248 !this.selectByValue(this.value, true) &&
15251 !this.store.lastOptions ||
15252 typeof(this.store.lastOptions.add) == 'undefined' ||
15253 this.store.lastOptions.add != true
15256 this.select(0, true);
15259 if(this.autoFocus){
15262 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
15263 this.taTask.delay(this.typeAheadDelay);
15267 this.onEmptyResults();
15273 onLoadException : function()
15275 this.hasQuery = false;
15277 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15278 this.loading.hide();
15281 if(this.tickable && this.editable){
15286 // only causes errors at present
15287 //Roo.log(this.store.reader.jsonData);
15288 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
15290 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
15296 onTypeAhead : function(){
15297 if(this.store.getCount() > 0){
15298 var r = this.store.getAt(0);
15299 var newValue = r.data[this.displayField];
15300 var len = newValue.length;
15301 var selStart = this.getRawValue().length;
15303 if(selStart != len){
15304 this.setRawValue(newValue);
15305 this.selectText(selStart, newValue.length);
15311 onSelect : function(record, index){
15313 if(this.fireEvent('beforeselect', this, record, index) !== false){
15315 this.setFromData(index > -1 ? record.data : false);
15318 this.fireEvent('select', this, record, index);
15323 * Returns the currently selected field value or empty string if no value is set.
15324 * @return {String} value The selected value
15326 getValue : function()
15328 if(Roo.isIOS && this.useNativeIOS){
15329 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
15333 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
15336 if(this.valueField){
15337 return typeof this.value != 'undefined' ? this.value : '';
15339 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
15343 getRawValue : function()
15345 if(Roo.isIOS && this.useNativeIOS){
15346 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
15349 var v = this.inputEl().getValue();
15355 * Clears any text/value currently set in the field
15357 clearValue : function(){
15359 if(this.hiddenField){
15360 this.hiddenField.dom.value = '';
15363 this.setRawValue('');
15364 this.lastSelectionText = '';
15365 this.lastData = false;
15367 var close = this.closeTriggerEl();
15378 * Sets the specified value into the field. If the value finds a match, the corresponding record text
15379 * will be displayed in the field. If the value does not match the data value of an existing item,
15380 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
15381 * Otherwise the field will be blank (although the value will still be set).
15382 * @param {String} value The value to match
15384 setValue : function(v)
15386 if(Roo.isIOS && this.useNativeIOS){
15387 this.setIOSValue(v);
15397 if(this.valueField){
15398 var r = this.findRecord(this.valueField, v);
15400 text = r.data[this.displayField];
15401 }else if(this.valueNotFoundText !== undefined){
15402 text = this.valueNotFoundText;
15405 this.lastSelectionText = text;
15406 if(this.hiddenField){
15407 this.hiddenField.dom.value = v;
15409 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
15412 var close = this.closeTriggerEl();
15415 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
15421 * @property {Object} the last set data for the element
15426 * Sets the value of the field based on a object which is related to the record format for the store.
15427 * @param {Object} value the value to set as. or false on reset?
15429 setFromData : function(o){
15436 var dv = ''; // display value
15437 var vv = ''; // value value..
15439 if (this.displayField) {
15440 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15442 // this is an error condition!!!
15443 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15446 if(this.valueField){
15447 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
15450 var close = this.closeTriggerEl();
15453 if(dv.length || vv * 1 > 0){
15455 this.blockFocus=true;
15461 if(this.hiddenField){
15462 this.hiddenField.dom.value = vv;
15464 this.lastSelectionText = dv;
15465 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
15469 // no hidden field.. - we store the value in 'value', but still display
15470 // display field!!!!
15471 this.lastSelectionText = dv;
15472 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
15479 reset : function(){
15480 // overridden so that last data is reset..
15487 this.setValue(this.originalValue);
15488 //this.clearInvalid();
15489 this.lastData = false;
15491 this.view.clearSelections();
15497 findRecord : function(prop, value){
15499 if(this.store.getCount() > 0){
15500 this.store.each(function(r){
15501 if(r.data[prop] == value){
15511 getName: function()
15513 // returns hidden if it's set..
15514 if (!this.rendered) {return ''};
15515 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
15519 onViewMove : function(e, t){
15520 this.inKeyMode = false;
15524 onViewOver : function(e, t){
15525 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
15528 var item = this.view.findItemFromChild(t);
15531 var index = this.view.indexOf(item);
15532 this.select(index, false);
15537 onViewClick : function(view, doFocus, el, e)
15539 var index = this.view.getSelectedIndexes()[0];
15541 var r = this.store.getAt(index);
15545 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
15552 Roo.each(this.tickItems, function(v,k){
15554 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
15556 _this.tickItems.splice(k, 1);
15558 if(typeof(e) == 'undefined' && view == false){
15559 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
15571 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
15572 this.tickItems.push(r.data);
15575 if(typeof(e) == 'undefined' && view == false){
15576 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
15583 this.onSelect(r, index);
15585 if(doFocus !== false && !this.blockFocus){
15586 this.inputEl().focus();
15591 restrictHeight : function(){
15592 //this.innerList.dom.style.height = '';
15593 //var inner = this.innerList.dom;
15594 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
15595 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
15596 //this.list.beginUpdate();
15597 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
15598 this.list.alignTo(this.inputEl(), this.listAlign);
15599 this.list.alignTo(this.inputEl(), this.listAlign);
15600 //this.list.endUpdate();
15604 onEmptyResults : function(){
15606 if(this.tickable && this.editable){
15607 this.hasFocus = false;
15608 this.restrictHeight();
15616 * Returns true if the dropdown list is expanded, else false.
15618 isExpanded : function(){
15619 return this.list.isVisible();
15623 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
15624 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
15625 * @param {String} value The data value of the item to select
15626 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
15627 * selected item if it is not currently in view (defaults to true)
15628 * @return {Boolean} True if the value matched an item in the list, else false
15630 selectByValue : function(v, scrollIntoView){
15631 if(v !== undefined && v !== null){
15632 var r = this.findRecord(this.valueField || this.displayField, v);
15634 this.select(this.store.indexOf(r), scrollIntoView);
15642 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
15643 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
15644 * @param {Number} index The zero-based index of the list item to select
15645 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
15646 * selected item if it is not currently in view (defaults to true)
15648 select : function(index, scrollIntoView){
15649 this.selectedIndex = index;
15650 this.view.select(index);
15651 if(scrollIntoView !== false){
15652 var el = this.view.getNode(index);
15654 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
15657 this.list.scrollChildIntoView(el, false);
15663 selectNext : function(){
15664 var ct = this.store.getCount();
15666 if(this.selectedIndex == -1){
15668 }else if(this.selectedIndex < ct-1){
15669 this.select(this.selectedIndex+1);
15675 selectPrev : function(){
15676 var ct = this.store.getCount();
15678 if(this.selectedIndex == -1){
15680 }else if(this.selectedIndex != 0){
15681 this.select(this.selectedIndex-1);
15687 onKeyUp : function(e){
15688 if(this.editable !== false && !e.isSpecialKey()){
15689 this.lastKey = e.getKey();
15690 this.dqTask.delay(this.queryDelay);
15695 validateBlur : function(){
15696 return !this.list || !this.list.isVisible();
15700 initQuery : function(){
15702 var v = this.getRawValue();
15704 if(this.tickable && this.editable){
15705 v = this.tickableInputEl().getValue();
15712 doForce : function(){
15713 if(this.inputEl().dom.value.length > 0){
15714 this.inputEl().dom.value =
15715 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
15721 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
15722 * query allowing the query action to be canceled if needed.
15723 * @param {String} query The SQL query to execute
15724 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
15725 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
15726 * saved in the current store (defaults to false)
15728 doQuery : function(q, forceAll){
15730 if(q === undefined || q === null){
15735 forceAll: forceAll,
15739 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
15744 forceAll = qe.forceAll;
15745 if(forceAll === true || (q.length >= this.minChars)){
15747 this.hasQuery = true;
15749 if(this.lastQuery != q || this.alwaysQuery){
15750 this.lastQuery = q;
15751 if(this.mode == 'local'){
15752 this.selectedIndex = -1;
15754 this.store.clearFilter();
15757 if(this.specialFilter){
15758 this.fireEvent('specialfilter', this);
15763 this.store.filter(this.displayField, q);
15766 this.store.fireEvent("datachanged", this.store);
15773 this.store.baseParams[this.queryParam] = q;
15775 var options = {params : this.getParams(q)};
15778 options.add = true;
15779 options.params.start = this.page * this.pageSize;
15782 this.store.load(options);
15785 * this code will make the page width larger, at the beginning, the list not align correctly,
15786 * we should expand the list on onLoad
15787 * so command out it
15792 this.selectedIndex = -1;
15797 this.loadNext = false;
15801 getParams : function(q){
15803 //p[this.queryParam] = q;
15807 p.limit = this.pageSize;
15813 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
15815 collapse : function(){
15816 if(!this.isExpanded()){
15822 this.hasFocus = false;
15826 this.cancelBtn.hide();
15827 this.trigger.show();
15830 this.tickableInputEl().dom.value = '';
15831 this.tickableInputEl().blur();
15836 Roo.get(document).un('mousedown', this.collapseIf, this);
15837 Roo.get(document).un('mousewheel', this.collapseIf, this);
15838 if (!this.editable) {
15839 Roo.get(document).un('keydown', this.listKeyPress, this);
15841 this.fireEvent('collapse', this);
15847 collapseIf : function(e){
15848 var in_combo = e.within(this.el);
15849 var in_list = e.within(this.list);
15850 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
15852 if (in_combo || in_list || is_list) {
15853 //e.stopPropagation();
15858 this.onTickableFooterButtonClick(e, false, false);
15866 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
15868 expand : function(){
15870 if(this.isExpanded() || !this.hasFocus){
15874 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
15875 this.list.setWidth(lw);
15881 this.restrictHeight();
15885 this.tickItems = Roo.apply([], this.item);
15888 this.cancelBtn.show();
15889 this.trigger.hide();
15892 this.tickableInputEl().focus();
15897 Roo.get(document).on('mousedown', this.collapseIf, this);
15898 Roo.get(document).on('mousewheel', this.collapseIf, this);
15899 if (!this.editable) {
15900 Roo.get(document).on('keydown', this.listKeyPress, this);
15903 this.fireEvent('expand', this);
15907 // Implements the default empty TriggerField.onTriggerClick function
15908 onTriggerClick : function(e)
15910 Roo.log('trigger click');
15912 if(this.disabled || !this.triggerList){
15917 this.loadNext = false;
15919 if(this.isExpanded()){
15921 if (!this.blockFocus) {
15922 this.inputEl().focus();
15926 this.hasFocus = true;
15927 if(this.triggerAction == 'all') {
15928 this.doQuery(this.allQuery, true);
15930 this.doQuery(this.getRawValue());
15932 if (!this.blockFocus) {
15933 this.inputEl().focus();
15938 onTickableTriggerClick : function(e)
15945 this.loadNext = false;
15946 this.hasFocus = true;
15948 if(this.triggerAction == 'all') {
15949 this.doQuery(this.allQuery, true);
15951 this.doQuery(this.getRawValue());
15955 onSearchFieldClick : function(e)
15957 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
15958 this.onTickableFooterButtonClick(e, false, false);
15962 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
15967 this.loadNext = false;
15968 this.hasFocus = true;
15970 if(this.triggerAction == 'all') {
15971 this.doQuery(this.allQuery, true);
15973 this.doQuery(this.getRawValue());
15977 listKeyPress : function(e)
15979 //Roo.log('listkeypress');
15980 // scroll to first matching element based on key pres..
15981 if (e.isSpecialKey()) {
15984 var k = String.fromCharCode(e.getKey()).toUpperCase();
15987 var csel = this.view.getSelectedNodes();
15988 var cselitem = false;
15990 var ix = this.view.indexOf(csel[0]);
15991 cselitem = this.store.getAt(ix);
15992 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15998 this.store.each(function(v) {
16000 // start at existing selection.
16001 if (cselitem.id == v.id) {
16007 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
16008 match = this.store.indexOf(v);
16014 if (match === false) {
16015 return true; // no more action?
16018 this.view.select(match);
16019 var sn = Roo.get(this.view.getSelectedNodes()[0]);
16020 sn.scrollIntoView(sn.dom.parentNode, false);
16023 onViewScroll : function(e, t){
16025 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){
16029 this.hasQuery = true;
16031 this.loading = this.list.select('.loading', true).first();
16033 if(this.loading === null){
16034 this.list.createChild({
16036 cls: 'loading roo-select2-more-results roo-select2-active',
16037 html: 'Loading more results...'
16040 this.loading = this.list.select('.loading', true).first();
16042 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
16044 this.loading.hide();
16047 this.loading.show();
16052 this.loadNext = true;
16054 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
16059 addItem : function(o)
16061 var dv = ''; // display value
16063 if (this.displayField) {
16064 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16066 // this is an error condition!!!
16067 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16074 var choice = this.choices.createChild({
16076 cls: 'roo-select2-search-choice',
16085 cls: 'roo-select2-search-choice-close fa fa-times',
16090 }, this.searchField);
16092 var close = choice.select('a.roo-select2-search-choice-close', true).first();
16094 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
16102 this.inputEl().dom.value = '';
16107 onRemoveItem : function(e, _self, o)
16109 e.preventDefault();
16111 this.lastItem = Roo.apply([], this.item);
16113 var index = this.item.indexOf(o.data) * 1;
16116 Roo.log('not this item?!');
16120 this.item.splice(index, 1);
16125 this.fireEvent('remove', this, e);
16131 syncValue : function()
16133 if(!this.item.length){
16140 Roo.each(this.item, function(i){
16141 if(_this.valueField){
16142 value.push(i[_this.valueField]);
16149 this.value = value.join(',');
16151 if(this.hiddenField){
16152 this.hiddenField.dom.value = this.value;
16155 this.store.fireEvent("datachanged", this.store);
16160 clearItem : function()
16162 if(!this.multiple){
16168 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
16176 if(this.tickable && !Roo.isTouch){
16177 this.view.refresh();
16181 inputEl: function ()
16183 if(Roo.isIOS && this.useNativeIOS){
16184 return this.el.select('select.roo-ios-select', true).first();
16187 if(Roo.isTouch && this.mobileTouchView){
16188 return this.el.select('input.form-control',true).first();
16192 return this.searchField;
16195 return this.el.select('input.form-control',true).first();
16198 onTickableFooterButtonClick : function(e, btn, el)
16200 e.preventDefault();
16202 this.lastItem = Roo.apply([], this.item);
16204 if(btn && btn.name == 'cancel'){
16205 this.tickItems = Roo.apply([], this.item);
16214 Roo.each(this.tickItems, function(o){
16222 validate : function()
16224 if(this.getVisibilityEl().hasClass('hidden')){
16228 var v = this.getRawValue();
16231 v = this.getValue();
16234 if(this.disabled || this.allowBlank || v.length){
16239 this.markInvalid();
16243 tickableInputEl : function()
16245 if(!this.tickable || !this.editable){
16246 return this.inputEl();
16249 return this.inputEl().select('.roo-select2-search-field-input', true).first();
16253 getAutoCreateTouchView : function()
16258 cls: 'form-group' //input-group
16264 type : this.inputType,
16265 cls : 'form-control x-combo-noedit',
16266 autocomplete: 'new-password',
16267 placeholder : this.placeholder || '',
16272 input.name = this.name;
16276 input.cls += ' input-' + this.size;
16279 if (this.disabled) {
16280 input.disabled = true;
16291 inputblock.cls += ' input-group';
16293 inputblock.cn.unshift({
16295 cls : 'input-group-addon input-group-prepend input-group-text',
16300 if(this.removable && !this.multiple){
16301 inputblock.cls += ' roo-removable';
16303 inputblock.cn.push({
16306 cls : 'roo-combo-removable-btn close'
16310 if(this.hasFeedback && !this.allowBlank){
16312 inputblock.cls += ' has-feedback';
16314 inputblock.cn.push({
16316 cls: 'glyphicon form-control-feedback'
16323 inputblock.cls += (this.before) ? '' : ' input-group';
16325 inputblock.cn.push({
16327 cls : 'input-group-addon input-group-append input-group-text',
16333 var ibwrap = inputblock;
16338 cls: 'roo-select2-choices',
16342 cls: 'roo-select2-search-field',
16355 cls: 'roo-select2-container input-group roo-touchview-combobox ',
16360 cls: 'form-hidden-field'
16366 if(!this.multiple && this.showToggleBtn){
16372 if (this.caret != false) {
16375 cls: 'fa fa-' + this.caret
16382 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
16384 Roo.bootstrap.version == 3 ? caret : '',
16387 cls: 'combobox-clear',
16401 combobox.cls += ' roo-select2-container-multi';
16404 var align = this.labelAlign || this.parentLabelAlign();
16406 if (align ==='left' && this.fieldLabel.length) {
16411 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
16412 tooltip : 'This field is required'
16416 cls : 'control-label col-form-label',
16417 html : this.fieldLabel
16428 var labelCfg = cfg.cn[1];
16429 var contentCfg = cfg.cn[2];
16432 if(this.indicatorpos == 'right'){
16437 cls : 'control-label col-form-label',
16441 html : this.fieldLabel
16445 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
16446 tooltip : 'This field is required'
16459 labelCfg = cfg.cn[0];
16460 contentCfg = cfg.cn[1];
16465 if(this.labelWidth > 12){
16466 labelCfg.style = "width: " + this.labelWidth + 'px';
16469 if(this.labelWidth < 13 && this.labelmd == 0){
16470 this.labelmd = this.labelWidth;
16473 if(this.labellg > 0){
16474 labelCfg.cls += ' col-lg-' + this.labellg;
16475 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
16478 if(this.labelmd > 0){
16479 labelCfg.cls += ' col-md-' + this.labelmd;
16480 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
16483 if(this.labelsm > 0){
16484 labelCfg.cls += ' col-sm-' + this.labelsm;
16485 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
16488 if(this.labelxs > 0){
16489 labelCfg.cls += ' col-xs-' + this.labelxs;
16490 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
16494 } else if ( this.fieldLabel.length) {
16498 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
16499 tooltip : 'This field is required'
16503 cls : 'control-label',
16504 html : this.fieldLabel
16515 if(this.indicatorpos == 'right'){
16519 cls : 'control-label',
16520 html : this.fieldLabel,
16524 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
16525 tooltip : 'This field is required'
16542 var settings = this;
16544 ['xs','sm','md','lg'].map(function(size){
16545 if (settings[size]) {
16546 cfg.cls += ' col-' + size + '-' + settings[size];
16553 initTouchView : function()
16555 this.renderTouchView();
16557 this.touchViewEl.on('scroll', function(){
16558 this.el.dom.scrollTop = 0;
16561 this.originalValue = this.getValue();
16563 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
16565 this.inputEl().on("click", this.showTouchView, this);
16566 if (this.triggerEl) {
16567 this.triggerEl.on("click", this.showTouchView, this);
16571 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
16572 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
16574 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
16576 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
16577 this.store.on('load', this.onTouchViewLoad, this);
16578 this.store.on('loadexception', this.onTouchViewLoadException, this);
16580 if(this.hiddenName){
16582 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
16584 this.hiddenField.dom.value =
16585 this.hiddenValue !== undefined ? this.hiddenValue :
16586 this.value !== undefined ? this.value : '';
16588 this.el.dom.removeAttribute('name');
16589 this.hiddenField.dom.setAttribute('name', this.hiddenName);
16593 this.choices = this.el.select('ul.roo-select2-choices', true).first();
16594 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
16597 if(this.removable && !this.multiple){
16598 var close = this.closeTriggerEl();
16600 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
16601 close.on('click', this.removeBtnClick, this, close);
16605 * fix the bug in Safari iOS8
16607 this.inputEl().on("focus", function(e){
16608 document.activeElement.blur();
16611 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
16618 renderTouchView : function()
16620 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
16621 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16623 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
16624 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16626 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
16627 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16628 this.touchViewBodyEl.setStyle('overflow', 'auto');
16630 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
16631 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16633 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
16634 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16638 showTouchView : function()
16644 this.touchViewHeaderEl.hide();
16646 if(this.modalTitle.length){
16647 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
16648 this.touchViewHeaderEl.show();
16651 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
16652 this.touchViewEl.show();
16654 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
16656 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
16657 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
16659 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
16661 if(this.modalTitle.length){
16662 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
16665 this.touchViewBodyEl.setHeight(bodyHeight);
16669 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
16671 this.touchViewEl.addClass('in');
16674 if(this._touchViewMask){
16675 Roo.get(document.body).addClass("x-body-masked");
16676 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
16677 this._touchViewMask.setStyle('z-index', 10000);
16678 this._touchViewMask.addClass('show');
16681 this.doTouchViewQuery();
16685 hideTouchView : function()
16687 this.touchViewEl.removeClass('in');
16691 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
16693 this.touchViewEl.setStyle('display', 'none');
16696 if(this._touchViewMask){
16697 this._touchViewMask.removeClass('show');
16698 Roo.get(document.body).removeClass("x-body-masked");
16702 setTouchViewValue : function()
16709 Roo.each(this.tickItems, function(o){
16714 this.hideTouchView();
16717 doTouchViewQuery : function()
16726 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
16730 if(!this.alwaysQuery || this.mode == 'local'){
16731 this.onTouchViewLoad();
16738 onTouchViewBeforeLoad : function(combo,opts)
16744 onTouchViewLoad : function()
16746 if(this.store.getCount() < 1){
16747 this.onTouchViewEmptyResults();
16751 this.clearTouchView();
16753 var rawValue = this.getRawValue();
16755 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
16757 this.tickItems = [];
16759 this.store.data.each(function(d, rowIndex){
16760 var row = this.touchViewListGroup.createChild(template);
16762 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
16763 row.addClass(d.data.cls);
16766 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16769 html : d.data[this.displayField]
16772 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
16773 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
16776 row.removeClass('selected');
16777 if(!this.multiple && this.valueField &&
16778 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
16781 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16782 row.addClass('selected');
16785 if(this.multiple && this.valueField &&
16786 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
16790 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16791 this.tickItems.push(d.data);
16794 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
16798 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
16800 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
16802 if(this.modalTitle.length){
16803 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
16806 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
16808 if(this.mobile_restrict_height && listHeight < bodyHeight){
16809 this.touchViewBodyEl.setHeight(listHeight);
16814 if(firstChecked && listHeight > bodyHeight){
16815 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
16820 onTouchViewLoadException : function()
16822 this.hideTouchView();
16825 onTouchViewEmptyResults : function()
16827 this.clearTouchView();
16829 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
16831 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
16835 clearTouchView : function()
16837 this.touchViewListGroup.dom.innerHTML = '';
16840 onTouchViewClick : function(e, el, o)
16842 e.preventDefault();
16845 var rowIndex = o.rowIndex;
16847 var r = this.store.getAt(rowIndex);
16849 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
16851 if(!this.multiple){
16852 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
16853 c.dom.removeAttribute('checked');
16856 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16858 this.setFromData(r.data);
16860 var close = this.closeTriggerEl();
16866 this.hideTouchView();
16868 this.fireEvent('select', this, r, rowIndex);
16873 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
16874 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
16875 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
16879 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
16880 this.addItem(r.data);
16881 this.tickItems.push(r.data);
16885 getAutoCreateNativeIOS : function()
16888 cls: 'form-group' //input-group,
16893 cls : 'roo-ios-select'
16897 combobox.name = this.name;
16900 if (this.disabled) {
16901 combobox.disabled = true;
16904 var settings = this;
16906 ['xs','sm','md','lg'].map(function(size){
16907 if (settings[size]) {
16908 cfg.cls += ' col-' + size + '-' + settings[size];
16918 initIOSView : function()
16920 this.store.on('load', this.onIOSViewLoad, this);
16925 onIOSViewLoad : function()
16927 if(this.store.getCount() < 1){
16931 this.clearIOSView();
16933 if(this.allowBlank) {
16935 var default_text = '-- SELECT --';
16937 if(this.placeholder.length){
16938 default_text = this.placeholder;
16941 if(this.emptyTitle.length){
16942 default_text += ' - ' + this.emptyTitle + ' -';
16945 var opt = this.inputEl().createChild({
16948 html : default_text
16952 o[this.valueField] = 0;
16953 o[this.displayField] = default_text;
16955 this.ios_options.push({
16962 this.store.data.each(function(d, rowIndex){
16966 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16967 html = d.data[this.displayField];
16972 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16973 value = d.data[this.valueField];
16982 if(this.value == d.data[this.valueField]){
16983 option['selected'] = true;
16986 var opt = this.inputEl().createChild(option);
16988 this.ios_options.push({
16995 this.inputEl().on('change', function(){
16996 this.fireEvent('select', this);
17001 clearIOSView: function()
17003 this.inputEl().dom.innerHTML = '';
17005 this.ios_options = [];
17008 setIOSValue: function(v)
17012 if(!this.ios_options){
17016 Roo.each(this.ios_options, function(opts){
17018 opts.el.dom.removeAttribute('selected');
17020 if(opts.data[this.valueField] != v){
17024 opts.el.dom.setAttribute('selected', true);
17030 * @cfg {Boolean} grow
17034 * @cfg {Number} growMin
17038 * @cfg {Number} growMax
17047 Roo.apply(Roo.bootstrap.ComboBox, {
17051 cls: 'modal-header',
17073 cls: 'list-group-item',
17077 cls: 'roo-combobox-list-group-item-value'
17081 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
17095 listItemCheckbox : {
17097 cls: 'list-group-item',
17101 cls: 'roo-combobox-list-group-item-value'
17105 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
17121 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
17126 cls: 'modal-footer',
17134 cls: 'col-xs-6 text-left',
17137 cls: 'btn btn-danger roo-touch-view-cancel',
17143 cls: 'col-xs-6 text-right',
17146 cls: 'btn btn-success roo-touch-view-ok',
17157 Roo.apply(Roo.bootstrap.ComboBox, {
17159 touchViewTemplate : {
17161 cls: 'modal fade roo-combobox-touch-view',
17165 cls: 'modal-dialog',
17166 style : 'position:fixed', // we have to fix position....
17170 cls: 'modal-content',
17172 Roo.bootstrap.ComboBox.header,
17173 Roo.bootstrap.ComboBox.body,
17174 Roo.bootstrap.ComboBox.footer
17183 * Ext JS Library 1.1.1
17184 * Copyright(c) 2006-2007, Ext JS, LLC.
17186 * Originally Released Under LGPL - original licence link has changed is not relivant.
17189 * <script type="text/javascript">
17194 * @extends Roo.util.Observable
17195 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
17196 * This class also supports single and multi selection modes. <br>
17197 * Create a data model bound view:
17199 var store = new Roo.data.Store(...);
17201 var view = new Roo.View({
17203 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
17205 singleSelect: true,
17206 selectedClass: "ydataview-selected",
17210 // listen for node click?
17211 view.on("click", function(vw, index, node, e){
17212 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
17216 dataModel.load("foobar.xml");
17218 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
17220 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
17221 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
17223 * Note: old style constructor is still suported (container, template, config)
17226 * Create a new View
17227 * @param {Object} config The config object
17230 Roo.View = function(config, depreciated_tpl, depreciated_config){
17232 this.parent = false;
17234 if (typeof(depreciated_tpl) == 'undefined') {
17235 // new way.. - universal constructor.
17236 Roo.apply(this, config);
17237 this.el = Roo.get(this.el);
17240 this.el = Roo.get(config);
17241 this.tpl = depreciated_tpl;
17242 Roo.apply(this, depreciated_config);
17244 this.wrapEl = this.el.wrap().wrap();
17245 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
17248 if(typeof(this.tpl) == "string"){
17249 this.tpl = new Roo.Template(this.tpl);
17251 // support xtype ctors..
17252 this.tpl = new Roo.factory(this.tpl, Roo);
17256 this.tpl.compile();
17261 * @event beforeclick
17262 * Fires before a click is processed. Returns false to cancel the default action.
17263 * @param {Roo.View} this
17264 * @param {Number} index The index of the target node
17265 * @param {HTMLElement} node The target node
17266 * @param {Roo.EventObject} e The raw event object
17268 "beforeclick" : true,
17271 * Fires when a template node is clicked.
17272 * @param {Roo.View} this
17273 * @param {Number} index The index of the target node
17274 * @param {HTMLElement} node The target node
17275 * @param {Roo.EventObject} e The raw event object
17280 * Fires when a template node is double clicked.
17281 * @param {Roo.View} this
17282 * @param {Number} index The index of the target node
17283 * @param {HTMLElement} node The target node
17284 * @param {Roo.EventObject} e The raw event object
17288 * @event contextmenu
17289 * Fires when a template node is right clicked.
17290 * @param {Roo.View} this
17291 * @param {Number} index The index of the target node
17292 * @param {HTMLElement} node The target node
17293 * @param {Roo.EventObject} e The raw event object
17295 "contextmenu" : true,
17297 * @event selectionchange
17298 * Fires when the selected nodes change.
17299 * @param {Roo.View} this
17300 * @param {Array} selections Array of the selected nodes
17302 "selectionchange" : true,
17305 * @event beforeselect
17306 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
17307 * @param {Roo.View} this
17308 * @param {HTMLElement} node The node to be selected
17309 * @param {Array} selections Array of currently selected nodes
17311 "beforeselect" : true,
17313 * @event preparedata
17314 * Fires on every row to render, to allow you to change the data.
17315 * @param {Roo.View} this
17316 * @param {Object} data to be rendered (change this)
17318 "preparedata" : true
17326 "click": this.onClick,
17327 "dblclick": this.onDblClick,
17328 "contextmenu": this.onContextMenu,
17332 this.selections = [];
17334 this.cmp = new Roo.CompositeElementLite([]);
17336 this.store = Roo.factory(this.store, Roo.data);
17337 this.setStore(this.store, true);
17340 if ( this.footer && this.footer.xtype) {
17342 var fctr = this.wrapEl.appendChild(document.createElement("div"));
17344 this.footer.dataSource = this.store;
17345 this.footer.container = fctr;
17346 this.footer = Roo.factory(this.footer, Roo);
17347 fctr.insertFirst(this.el);
17349 // this is a bit insane - as the paging toolbar seems to detach the el..
17350 // dom.parentNode.parentNode.parentNode
17351 // they get detached?
17355 Roo.View.superclass.constructor.call(this);
17360 Roo.extend(Roo.View, Roo.util.Observable, {
17363 * @cfg {Roo.data.Store} store Data store to load data from.
17368 * @cfg {String|Roo.Element} el The container element.
17373 * @cfg {String|Roo.Template} tpl The template used by this View
17377 * @cfg {String} dataName the named area of the template to use as the data area
17378 * Works with domtemplates roo-name="name"
17382 * @cfg {String} selectedClass The css class to add to selected nodes
17384 selectedClass : "x-view-selected",
17386 * @cfg {String} emptyText The empty text to show when nothing is loaded.
17391 * @cfg {String} text to display on mask (default Loading)
17395 * @cfg {Boolean} multiSelect Allow multiple selection
17397 multiSelect : false,
17399 * @cfg {Boolean} singleSelect Allow single selection
17401 singleSelect: false,
17404 * @cfg {Boolean} toggleSelect - selecting
17406 toggleSelect : false,
17409 * @cfg {Boolean} tickable - selecting
17414 * Returns the element this view is bound to.
17415 * @return {Roo.Element}
17417 getEl : function(){
17418 return this.wrapEl;
17424 * Refreshes the view. - called by datachanged on the store. - do not call directly.
17426 refresh : function(){
17427 //Roo.log('refresh');
17430 // if we are using something like 'domtemplate', then
17431 // the what gets used is:
17432 // t.applySubtemplate(NAME, data, wrapping data..)
17433 // the outer template then get' applied with
17434 // the store 'extra data'
17435 // and the body get's added to the
17436 // roo-name="data" node?
17437 // <span class='roo-tpl-{name}'></span> ?????
17441 this.clearSelections();
17442 this.el.update("");
17444 var records = this.store.getRange();
17445 if(records.length < 1) {
17447 // is this valid?? = should it render a template??
17449 this.el.update(this.emptyText);
17453 if (this.dataName) {
17454 this.el.update(t.apply(this.store.meta)); //????
17455 el = this.el.child('.roo-tpl-' + this.dataName);
17458 for(var i = 0, len = records.length; i < len; i++){
17459 var data = this.prepareData(records[i].data, i, records[i]);
17460 this.fireEvent("preparedata", this, data, i, records[i]);
17462 var d = Roo.apply({}, data);
17465 Roo.apply(d, {'roo-id' : Roo.id()});
17469 Roo.each(this.parent.item, function(item){
17470 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
17473 Roo.apply(d, {'roo-data-checked' : 'checked'});
17477 html[html.length] = Roo.util.Format.trim(
17479 t.applySubtemplate(this.dataName, d, this.store.meta) :
17486 el.update(html.join(""));
17487 this.nodes = el.dom.childNodes;
17488 this.updateIndexes(0);
17493 * Function to override to reformat the data that is sent to
17494 * the template for each node.
17495 * DEPRICATED - use the preparedata event handler.
17496 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
17497 * a JSON object for an UpdateManager bound view).
17499 prepareData : function(data, index, record)
17501 this.fireEvent("preparedata", this, data, index, record);
17505 onUpdate : function(ds, record){
17506 // Roo.log('on update');
17507 this.clearSelections();
17508 var index = this.store.indexOf(record);
17509 var n = this.nodes[index];
17510 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
17511 n.parentNode.removeChild(n);
17512 this.updateIndexes(index, index);
17518 onAdd : function(ds, records, index)
17520 //Roo.log(['on Add', ds, records, index] );
17521 this.clearSelections();
17522 if(this.nodes.length == 0){
17526 var n = this.nodes[index];
17527 for(var i = 0, len = records.length; i < len; i++){
17528 var d = this.prepareData(records[i].data, i, records[i]);
17530 this.tpl.insertBefore(n, d);
17533 this.tpl.append(this.el, d);
17536 this.updateIndexes(index);
17539 onRemove : function(ds, record, index){
17540 // Roo.log('onRemove');
17541 this.clearSelections();
17542 var el = this.dataName ?
17543 this.el.child('.roo-tpl-' + this.dataName) :
17546 el.dom.removeChild(this.nodes[index]);
17547 this.updateIndexes(index);
17551 * Refresh an individual node.
17552 * @param {Number} index
17554 refreshNode : function(index){
17555 this.onUpdate(this.store, this.store.getAt(index));
17558 updateIndexes : function(startIndex, endIndex){
17559 var ns = this.nodes;
17560 startIndex = startIndex || 0;
17561 endIndex = endIndex || ns.length - 1;
17562 for(var i = startIndex; i <= endIndex; i++){
17563 ns[i].nodeIndex = i;
17568 * Changes the data store this view uses and refresh the view.
17569 * @param {Store} store
17571 setStore : function(store, initial){
17572 if(!initial && this.store){
17573 this.store.un("datachanged", this.refresh);
17574 this.store.un("add", this.onAdd);
17575 this.store.un("remove", this.onRemove);
17576 this.store.un("update", this.onUpdate);
17577 this.store.un("clear", this.refresh);
17578 this.store.un("beforeload", this.onBeforeLoad);
17579 this.store.un("load", this.onLoad);
17580 this.store.un("loadexception", this.onLoad);
17584 store.on("datachanged", this.refresh, this);
17585 store.on("add", this.onAdd, this);
17586 store.on("remove", this.onRemove, this);
17587 store.on("update", this.onUpdate, this);
17588 store.on("clear", this.refresh, this);
17589 store.on("beforeload", this.onBeforeLoad, this);
17590 store.on("load", this.onLoad, this);
17591 store.on("loadexception", this.onLoad, this);
17599 * onbeforeLoad - masks the loading area.
17602 onBeforeLoad : function(store,opts)
17604 //Roo.log('onBeforeLoad');
17606 this.el.update("");
17608 this.el.mask(this.mask ? this.mask : "Loading" );
17610 onLoad : function ()
17617 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
17618 * @param {HTMLElement} node
17619 * @return {HTMLElement} The template node
17621 findItemFromChild : function(node){
17622 var el = this.dataName ?
17623 this.el.child('.roo-tpl-' + this.dataName,true) :
17626 if(!node || node.parentNode == el){
17629 var p = node.parentNode;
17630 while(p && p != el){
17631 if(p.parentNode == el){
17640 onClick : function(e){
17641 var item = this.findItemFromChild(e.getTarget());
17643 var index = this.indexOf(item);
17644 if(this.onItemClick(item, index, e) !== false){
17645 this.fireEvent("click", this, index, item, e);
17648 this.clearSelections();
17653 onContextMenu : function(e){
17654 var item = this.findItemFromChild(e.getTarget());
17656 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
17661 onDblClick : function(e){
17662 var item = this.findItemFromChild(e.getTarget());
17664 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
17668 onItemClick : function(item, index, e)
17670 if(this.fireEvent("beforeclick", this, index, item, e) === false){
17673 if (this.toggleSelect) {
17674 var m = this.isSelected(item) ? 'unselect' : 'select';
17677 _t[m](item, true, false);
17680 if(this.multiSelect || this.singleSelect){
17681 if(this.multiSelect && e.shiftKey && this.lastSelection){
17682 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
17684 this.select(item, this.multiSelect && e.ctrlKey);
17685 this.lastSelection = item;
17688 if(!this.tickable){
17689 e.preventDefault();
17697 * Get the number of selected nodes.
17700 getSelectionCount : function(){
17701 return this.selections.length;
17705 * Get the currently selected nodes.
17706 * @return {Array} An array of HTMLElements
17708 getSelectedNodes : function(){
17709 return this.selections;
17713 * Get the indexes of the selected nodes.
17716 getSelectedIndexes : function(){
17717 var indexes = [], s = this.selections;
17718 for(var i = 0, len = s.length; i < len; i++){
17719 indexes.push(s[i].nodeIndex);
17725 * Clear all selections
17726 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
17728 clearSelections : function(suppressEvent){
17729 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
17730 this.cmp.elements = this.selections;
17731 this.cmp.removeClass(this.selectedClass);
17732 this.selections = [];
17733 if(!suppressEvent){
17734 this.fireEvent("selectionchange", this, this.selections);
17740 * Returns true if the passed node is selected
17741 * @param {HTMLElement/Number} node The node or node index
17742 * @return {Boolean}
17744 isSelected : function(node){
17745 var s = this.selections;
17749 node = this.getNode(node);
17750 return s.indexOf(node) !== -1;
17755 * @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
17756 * @param {Boolean} keepExisting (optional) true to keep existing selections
17757 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
17759 select : function(nodeInfo, keepExisting, suppressEvent){
17760 if(nodeInfo instanceof Array){
17762 this.clearSelections(true);
17764 for(var i = 0, len = nodeInfo.length; i < len; i++){
17765 this.select(nodeInfo[i], true, true);
17769 var node = this.getNode(nodeInfo);
17770 if(!node || this.isSelected(node)){
17771 return; // already selected.
17774 this.clearSelections(true);
17777 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
17778 Roo.fly(node).addClass(this.selectedClass);
17779 this.selections.push(node);
17780 if(!suppressEvent){
17781 this.fireEvent("selectionchange", this, this.selections);
17789 * @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
17790 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
17791 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
17793 unselect : function(nodeInfo, keepExisting, suppressEvent)
17795 if(nodeInfo instanceof Array){
17796 Roo.each(this.selections, function(s) {
17797 this.unselect(s, nodeInfo);
17801 var node = this.getNode(nodeInfo);
17802 if(!node || !this.isSelected(node)){
17803 //Roo.log("not selected");
17804 return; // not selected.
17808 Roo.each(this.selections, function(s) {
17810 Roo.fly(node).removeClass(this.selectedClass);
17817 this.selections= ns;
17818 this.fireEvent("selectionchange", this, this.selections);
17822 * Gets a template node.
17823 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
17824 * @return {HTMLElement} The node or null if it wasn't found
17826 getNode : function(nodeInfo){
17827 if(typeof nodeInfo == "string"){
17828 return document.getElementById(nodeInfo);
17829 }else if(typeof nodeInfo == "number"){
17830 return this.nodes[nodeInfo];
17836 * Gets a range template nodes.
17837 * @param {Number} startIndex
17838 * @param {Number} endIndex
17839 * @return {Array} An array of nodes
17841 getNodes : function(start, end){
17842 var ns = this.nodes;
17843 start = start || 0;
17844 end = typeof end == "undefined" ? ns.length - 1 : end;
17847 for(var i = start; i <= end; i++){
17851 for(var i = start; i >= end; i--){
17859 * Finds the index of the passed node
17860 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
17861 * @return {Number} The index of the node or -1
17863 indexOf : function(node){
17864 node = this.getNode(node);
17865 if(typeof node.nodeIndex == "number"){
17866 return node.nodeIndex;
17868 var ns = this.nodes;
17869 for(var i = 0, len = ns.length; i < len; i++){
17880 * based on jquery fullcalendar
17884 Roo.bootstrap = Roo.bootstrap || {};
17886 * @class Roo.bootstrap.Calendar
17887 * @extends Roo.bootstrap.Component
17888 * Bootstrap Calendar class
17889 * @cfg {Boolean} loadMask (true|false) default false
17890 * @cfg {Object} header generate the user specific header of the calendar, default false
17893 * Create a new Container
17894 * @param {Object} config The config object
17899 Roo.bootstrap.Calendar = function(config){
17900 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
17904 * Fires when a date is selected
17905 * @param {DatePicker} this
17906 * @param {Date} date The selected date
17910 * @event monthchange
17911 * Fires when the displayed month changes
17912 * @param {DatePicker} this
17913 * @param {Date} date The selected month
17915 'monthchange': true,
17917 * @event evententer
17918 * Fires when mouse over an event
17919 * @param {Calendar} this
17920 * @param {event} Event
17922 'evententer': true,
17924 * @event eventleave
17925 * Fires when the mouse leaves an
17926 * @param {Calendar} this
17929 'eventleave': true,
17931 * @event eventclick
17932 * Fires when the mouse click an
17933 * @param {Calendar} this
17942 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
17945 * @cfg {Number} startDay
17946 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
17954 getAutoCreate : function(){
17957 var fc_button = function(name, corner, style, content ) {
17958 return Roo.apply({},{
17960 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
17962 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
17965 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17976 style : 'width:100%',
17983 cls : 'fc-header-left',
17985 fc_button('prev', 'left', 'arrow', '‹' ),
17986 fc_button('next', 'right', 'arrow', '›' ),
17987 { tag: 'span', cls: 'fc-header-space' },
17988 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17996 cls : 'fc-header-center',
18000 cls: 'fc-header-title',
18003 html : 'month / year'
18011 cls : 'fc-header-right',
18013 /* fc_button('month', 'left', '', 'month' ),
18014 fc_button('week', '', '', 'week' ),
18015 fc_button('day', 'right', '', 'day' )
18027 header = this.header;
18030 var cal_heads = function() {
18032 // fixme - handle this.
18034 for (var i =0; i < Date.dayNames.length; i++) {
18035 var d = Date.dayNames[i];
18038 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
18039 html : d.substring(0,3)
18043 ret[0].cls += ' fc-first';
18044 ret[6].cls += ' fc-last';
18047 var cal_cell = function(n) {
18050 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
18055 cls: 'fc-day-number',
18059 cls: 'fc-day-content',
18063 style: 'position: relative;' // height: 17px;
18075 var cal_rows = function() {
18078 for (var r = 0; r < 6; r++) {
18085 for (var i =0; i < Date.dayNames.length; i++) {
18086 var d = Date.dayNames[i];
18087 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
18090 row.cn[0].cls+=' fc-first';
18091 row.cn[0].cn[0].style = 'min-height:90px';
18092 row.cn[6].cls+=' fc-last';
18096 ret[0].cls += ' fc-first';
18097 ret[4].cls += ' fc-prev-last';
18098 ret[5].cls += ' fc-last';
18105 cls: 'fc-border-separate',
18106 style : 'width:100%',
18114 cls : 'fc-first fc-last',
18132 cls : 'fc-content',
18133 style : "position: relative;",
18136 cls : 'fc-view fc-view-month fc-grid',
18137 style : 'position: relative',
18138 unselectable : 'on',
18141 cls : 'fc-event-container',
18142 style : 'position:absolute;z-index:8;top:0;left:0;'
18160 initEvents : function()
18163 throw "can not find store for calendar";
18169 style: "text-align:center",
18173 style: "background-color:white;width:50%;margin:250 auto",
18177 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
18188 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
18190 var size = this.el.select('.fc-content', true).first().getSize();
18191 this.maskEl.setSize(size.width, size.height);
18192 this.maskEl.enableDisplayMode("block");
18193 if(!this.loadMask){
18194 this.maskEl.hide();
18197 this.store = Roo.factory(this.store, Roo.data);
18198 this.store.on('load', this.onLoad, this);
18199 this.store.on('beforeload', this.onBeforeLoad, this);
18203 this.cells = this.el.select('.fc-day',true);
18204 //Roo.log(this.cells);
18205 this.textNodes = this.el.query('.fc-day-number');
18206 this.cells.addClassOnOver('fc-state-hover');
18208 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
18209 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
18210 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
18211 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
18213 this.on('monthchange', this.onMonthChange, this);
18215 this.update(new Date().clearTime());
18218 resize : function() {
18219 var sz = this.el.getSize();
18221 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
18222 this.el.select('.fc-day-content div',true).setHeight(34);
18227 showPrevMonth : function(e){
18228 this.update(this.activeDate.add("mo", -1));
18230 showToday : function(e){
18231 this.update(new Date().clearTime());
18234 showNextMonth : function(e){
18235 this.update(this.activeDate.add("mo", 1));
18239 showPrevYear : function(){
18240 this.update(this.activeDate.add("y", -1));
18244 showNextYear : function(){
18245 this.update(this.activeDate.add("y", 1));
18250 update : function(date)
18252 var vd = this.activeDate;
18253 this.activeDate = date;
18254 // if(vd && this.el){
18255 // var t = date.getTime();
18256 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
18257 // Roo.log('using add remove');
18259 // this.fireEvent('monthchange', this, date);
18261 // this.cells.removeClass("fc-state-highlight");
18262 // this.cells.each(function(c){
18263 // if(c.dateValue == t){
18264 // c.addClass("fc-state-highlight");
18265 // setTimeout(function(){
18266 // try{c.dom.firstChild.focus();}catch(e){}
18276 var days = date.getDaysInMonth();
18278 var firstOfMonth = date.getFirstDateOfMonth();
18279 var startingPos = firstOfMonth.getDay()-this.startDay;
18281 if(startingPos < this.startDay){
18285 var pm = date.add(Date.MONTH, -1);
18286 var prevStart = pm.getDaysInMonth()-startingPos;
18288 this.cells = this.el.select('.fc-day',true);
18289 this.textNodes = this.el.query('.fc-day-number');
18290 this.cells.addClassOnOver('fc-state-hover');
18292 var cells = this.cells.elements;
18293 var textEls = this.textNodes;
18295 Roo.each(cells, function(cell){
18296 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
18299 days += startingPos;
18301 // convert everything to numbers so it's fast
18302 var day = 86400000;
18303 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
18306 //Roo.log(prevStart);
18308 var today = new Date().clearTime().getTime();
18309 var sel = date.clearTime().getTime();
18310 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
18311 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
18312 var ddMatch = this.disabledDatesRE;
18313 var ddText = this.disabledDatesText;
18314 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
18315 var ddaysText = this.disabledDaysText;
18316 var format = this.format;
18318 var setCellClass = function(cal, cell){
18322 //Roo.log('set Cell Class');
18324 var t = d.getTime();
18328 cell.dateValue = t;
18330 cell.className += " fc-today";
18331 cell.className += " fc-state-highlight";
18332 cell.title = cal.todayText;
18335 // disable highlight in other month..
18336 //cell.className += " fc-state-highlight";
18341 cell.className = " fc-state-disabled";
18342 cell.title = cal.minText;
18346 cell.className = " fc-state-disabled";
18347 cell.title = cal.maxText;
18351 if(ddays.indexOf(d.getDay()) != -1){
18352 cell.title = ddaysText;
18353 cell.className = " fc-state-disabled";
18356 if(ddMatch && format){
18357 var fvalue = d.dateFormat(format);
18358 if(ddMatch.test(fvalue)){
18359 cell.title = ddText.replace("%0", fvalue);
18360 cell.className = " fc-state-disabled";
18364 if (!cell.initialClassName) {
18365 cell.initialClassName = cell.dom.className;
18368 cell.dom.className = cell.initialClassName + ' ' + cell.className;
18373 for(; i < startingPos; i++) {
18374 textEls[i].innerHTML = (++prevStart);
18375 d.setDate(d.getDate()+1);
18377 cells[i].className = "fc-past fc-other-month";
18378 setCellClass(this, cells[i]);
18383 for(; i < days; i++){
18384 intDay = i - startingPos + 1;
18385 textEls[i].innerHTML = (intDay);
18386 d.setDate(d.getDate()+1);
18388 cells[i].className = ''; // "x-date-active";
18389 setCellClass(this, cells[i]);
18393 for(; i < 42; i++) {
18394 textEls[i].innerHTML = (++extraDays);
18395 d.setDate(d.getDate()+1);
18397 cells[i].className = "fc-future fc-other-month";
18398 setCellClass(this, cells[i]);
18401 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
18403 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
18405 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
18406 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
18408 if(totalRows != 6){
18409 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
18410 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
18413 this.fireEvent('monthchange', this, date);
18417 if(!this.internalRender){
18418 var main = this.el.dom.firstChild;
18419 var w = main.offsetWidth;
18420 this.el.setWidth(w + this.el.getBorderWidth("lr"));
18421 Roo.fly(main).setWidth(w);
18422 this.internalRender = true;
18423 // opera does not respect the auto grow header center column
18424 // then, after it gets a width opera refuses to recalculate
18425 // without a second pass
18426 if(Roo.isOpera && !this.secondPass){
18427 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
18428 this.secondPass = true;
18429 this.update.defer(10, this, [date]);
18436 findCell : function(dt) {
18437 dt = dt.clearTime().getTime();
18439 this.cells.each(function(c){
18440 //Roo.log("check " +c.dateValue + '?=' + dt);
18441 if(c.dateValue == dt){
18451 findCells : function(ev) {
18452 var s = ev.start.clone().clearTime().getTime();
18454 var e= ev.end.clone().clearTime().getTime();
18457 this.cells.each(function(c){
18458 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
18460 if(c.dateValue > e){
18463 if(c.dateValue < s){
18472 // findBestRow: function(cells)
18476 // for (var i =0 ; i < cells.length;i++) {
18477 // ret = Math.max(cells[i].rows || 0,ret);
18484 addItem : function(ev)
18486 // look for vertical location slot in
18487 var cells = this.findCells(ev);
18489 // ev.row = this.findBestRow(cells);
18491 // work out the location.
18495 for(var i =0; i < cells.length; i++) {
18497 cells[i].row = cells[0].row;
18500 cells[i].row = cells[i].row + 1;
18510 if (crow.start.getY() == cells[i].getY()) {
18512 crow.end = cells[i];
18529 cells[0].events.push(ev);
18531 this.calevents.push(ev);
18534 clearEvents: function() {
18536 if(!this.calevents){
18540 Roo.each(this.cells.elements, function(c){
18546 Roo.each(this.calevents, function(e) {
18547 Roo.each(e.els, function(el) {
18548 el.un('mouseenter' ,this.onEventEnter, this);
18549 el.un('mouseleave' ,this.onEventLeave, this);
18554 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
18560 renderEvents: function()
18564 this.cells.each(function(c) {
18573 if(c.row != c.events.length){
18574 r = 4 - (4 - (c.row - c.events.length));
18577 c.events = ev.slice(0, r);
18578 c.more = ev.slice(r);
18580 if(c.more.length && c.more.length == 1){
18581 c.events.push(c.more.pop());
18584 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
18588 this.cells.each(function(c) {
18590 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
18593 for (var e = 0; e < c.events.length; e++){
18594 var ev = c.events[e];
18595 var rows = ev.rows;
18597 for(var i = 0; i < rows.length; i++) {
18599 // how many rows should it span..
18602 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
18603 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
18605 unselectable : "on",
18608 cls: 'fc-event-inner',
18612 // cls: 'fc-event-time',
18613 // html : cells.length > 1 ? '' : ev.time
18617 cls: 'fc-event-title',
18618 html : String.format('{0}', ev.title)
18625 cls: 'ui-resizable-handle ui-resizable-e',
18626 html : '  '
18633 cfg.cls += ' fc-event-start';
18635 if ((i+1) == rows.length) {
18636 cfg.cls += ' fc-event-end';
18639 var ctr = _this.el.select('.fc-event-container',true).first();
18640 var cg = ctr.createChild(cfg);
18642 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
18643 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
18645 var r = (c.more.length) ? 1 : 0;
18646 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
18647 cg.setWidth(ebox.right - sbox.x -2);
18649 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
18650 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
18651 cg.on('click', _this.onEventClick, _this, ev);
18662 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
18663 style : 'position: absolute',
18664 unselectable : "on",
18667 cls: 'fc-event-inner',
18671 cls: 'fc-event-title',
18679 cls: 'ui-resizable-handle ui-resizable-e',
18680 html : '  '
18686 var ctr = _this.el.select('.fc-event-container',true).first();
18687 var cg = ctr.createChild(cfg);
18689 var sbox = c.select('.fc-day-content',true).first().getBox();
18690 var ebox = c.select('.fc-day-content',true).first().getBox();
18692 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
18693 cg.setWidth(ebox.right - sbox.x -2);
18695 cg.on('click', _this.onMoreEventClick, _this, c.more);
18705 onEventEnter: function (e, el,event,d) {
18706 this.fireEvent('evententer', this, el, event);
18709 onEventLeave: function (e, el,event,d) {
18710 this.fireEvent('eventleave', this, el, event);
18713 onEventClick: function (e, el,event,d) {
18714 this.fireEvent('eventclick', this, el, event);
18717 onMonthChange: function () {
18721 onMoreEventClick: function(e, el, more)
18725 this.calpopover.placement = 'right';
18726 this.calpopover.setTitle('More');
18728 this.calpopover.setContent('');
18730 var ctr = this.calpopover.el.select('.popover-content', true).first();
18732 Roo.each(more, function(m){
18734 cls : 'fc-event-hori fc-event-draggable',
18737 var cg = ctr.createChild(cfg);
18739 cg.on('click', _this.onEventClick, _this, m);
18742 this.calpopover.show(el);
18747 onLoad: function ()
18749 this.calevents = [];
18752 if(this.store.getCount() > 0){
18753 this.store.data.each(function(d){
18756 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
18757 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
18758 time : d.data.start_time,
18759 title : d.data.title,
18760 description : d.data.description,
18761 venue : d.data.venue
18766 this.renderEvents();
18768 if(this.calevents.length && this.loadMask){
18769 this.maskEl.hide();
18773 onBeforeLoad: function()
18775 this.clearEvents();
18777 this.maskEl.show();
18791 * @class Roo.bootstrap.Popover
18792 * @extends Roo.bootstrap.Component
18793 * Bootstrap Popover class
18794 * @cfg {String} html contents of the popover (or false to use children..)
18795 * @cfg {String} title of popover (or false to hide)
18796 * @cfg {String} placement how it is placed
18797 * @cfg {String} trigger click || hover (or false to trigger manually)
18798 * @cfg {String} over what (parent or false to trigger manually.)
18799 * @cfg {Number} delay - delay before showing
18802 * Create a new Popover
18803 * @param {Object} config The config object
18806 Roo.bootstrap.Popover = function(config){
18807 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
18813 * After the popover show
18815 * @param {Roo.bootstrap.Popover} this
18820 * After the popover hide
18822 * @param {Roo.bootstrap.Popover} this
18828 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
18830 title: 'Fill in a title',
18833 placement : 'right',
18834 trigger : 'hover', // hover
18840 can_build_overlaid : false,
18842 getChildContainer : function()
18844 return this.el.select('.popover-content',true).first();
18847 getAutoCreate : function(){
18850 cls : 'popover roo-dynamic',
18851 style: 'display:block',
18857 cls : 'popover-inner',
18861 cls: 'popover-title popover-header',
18865 cls : 'popover-content popover-body',
18876 setTitle: function(str)
18879 this.el.select('.popover-title',true).first().dom.innerHTML = str;
18881 setContent: function(str)
18884 this.el.select('.popover-content',true).first().dom.innerHTML = str;
18886 // as it get's added to the bottom of the page.
18887 onRender : function(ct, position)
18889 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18891 var cfg = Roo.apply({}, this.getAutoCreate());
18895 cfg.cls += ' ' + this.cls;
18898 cfg.style = this.style;
18900 //Roo.log("adding to ");
18901 this.el = Roo.get(document.body).createChild(cfg, position);
18902 // Roo.log(this.el);
18907 initEvents : function()
18909 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
18910 this.el.enableDisplayMode('block');
18912 if (this.over === false) {
18915 if (this.triggers === false) {
18918 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18919 var triggers = this.trigger ? this.trigger.split(' ') : [];
18920 Roo.each(triggers, function(trigger) {
18922 if (trigger == 'click') {
18923 on_el.on('click', this.toggle, this);
18924 } else if (trigger != 'manual') {
18925 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
18926 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
18928 on_el.on(eventIn ,this.enter, this);
18929 on_el.on(eventOut, this.leave, this);
18940 toggle : function () {
18941 this.hoverState == 'in' ? this.leave() : this.enter();
18944 enter : function () {
18946 clearTimeout(this.timeout);
18948 this.hoverState = 'in';
18950 if (!this.delay || !this.delay.show) {
18955 this.timeout = setTimeout(function () {
18956 if (_t.hoverState == 'in') {
18959 }, this.delay.show)
18962 leave : function() {
18963 clearTimeout(this.timeout);
18965 this.hoverState = 'out';
18967 if (!this.delay || !this.delay.hide) {
18972 this.timeout = setTimeout(function () {
18973 if (_t.hoverState == 'out') {
18976 }, this.delay.hide)
18979 show : function (on_el)
18982 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18986 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18987 if (this.html !== false) {
18988 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18990 this.el.removeClass([
18991 'fade','top','bottom', 'left', 'right','in',
18992 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18994 if (!this.title.length) {
18995 this.el.select('.popover-title',true).hide();
18998 var placement = typeof this.placement == 'function' ?
18999 this.placement.call(this, this.el, on_el) :
19002 var autoToken = /\s?auto?\s?/i;
19003 var autoPlace = autoToken.test(placement);
19005 placement = placement.replace(autoToken, '') || 'top';
19009 //this.el.setXY([0,0]);
19011 this.el.dom.style.display='block';
19012 this.el.addClass(placement);
19014 //this.el.appendTo(on_el);
19016 var p = this.getPosition();
19017 var box = this.el.getBox();
19022 var align = Roo.bootstrap.Popover.alignment[placement];
19025 this.el.alignTo(on_el, align[0],align[1]);
19026 //var arrow = this.el.select('.arrow',true).first();
19027 //arrow.set(align[2],
19029 this.el.addClass('in');
19032 if (this.el.hasClass('fade')) {
19036 this.hoverState = 'in';
19038 this.fireEvent('show', this);
19043 this.el.setXY([0,0]);
19044 this.el.removeClass('in');
19046 this.hoverState = null;
19048 this.fireEvent('hide', this);
19053 Roo.bootstrap.Popover.alignment = {
19054 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
19055 'right' : ['l-r', [10,0], 'left bs-popover-left'],
19056 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
19057 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
19068 * @class Roo.bootstrap.Progress
19069 * @extends Roo.bootstrap.Component
19070 * Bootstrap Progress class
19071 * @cfg {Boolean} striped striped of the progress bar
19072 * @cfg {Boolean} active animated of the progress bar
19076 * Create a new Progress
19077 * @param {Object} config The config object
19080 Roo.bootstrap.Progress = function(config){
19081 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
19084 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
19089 getAutoCreate : function(){
19097 cfg.cls += ' progress-striped';
19101 cfg.cls += ' active';
19120 * @class Roo.bootstrap.ProgressBar
19121 * @extends Roo.bootstrap.Component
19122 * Bootstrap ProgressBar class
19123 * @cfg {Number} aria_valuenow aria-value now
19124 * @cfg {Number} aria_valuemin aria-value min
19125 * @cfg {Number} aria_valuemax aria-value max
19126 * @cfg {String} label label for the progress bar
19127 * @cfg {String} panel (success | info | warning | danger )
19128 * @cfg {String} role role of the progress bar
19129 * @cfg {String} sr_only text
19133 * Create a new ProgressBar
19134 * @param {Object} config The config object
19137 Roo.bootstrap.ProgressBar = function(config){
19138 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
19141 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
19145 aria_valuemax : 100,
19151 getAutoCreate : function()
19156 cls: 'progress-bar',
19157 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
19169 cfg.role = this.role;
19172 if(this.aria_valuenow){
19173 cfg['aria-valuenow'] = this.aria_valuenow;
19176 if(this.aria_valuemin){
19177 cfg['aria-valuemin'] = this.aria_valuemin;
19180 if(this.aria_valuemax){
19181 cfg['aria-valuemax'] = this.aria_valuemax;
19184 if(this.label && !this.sr_only){
19185 cfg.html = this.label;
19189 cfg.cls += ' progress-bar-' + this.panel;
19195 update : function(aria_valuenow)
19197 this.aria_valuenow = aria_valuenow;
19199 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
19214 * @class Roo.bootstrap.TabGroup
19215 * @extends Roo.bootstrap.Column
19216 * Bootstrap Column class
19217 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
19218 * @cfg {Boolean} carousel true to make the group behave like a carousel
19219 * @cfg {Boolean} bullets show bullets for the panels
19220 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
19221 * @cfg {Number} timer auto slide timer .. default 0 millisecond
19222 * @cfg {Boolean} showarrow (true|false) show arrow default true
19225 * Create a new TabGroup
19226 * @param {Object} config The config object
19229 Roo.bootstrap.TabGroup = function(config){
19230 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
19232 this.navId = Roo.id();
19235 Roo.bootstrap.TabGroup.register(this);
19239 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
19242 transition : false,
19247 slideOnTouch : false,
19250 getAutoCreate : function()
19252 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
19254 cfg.cls += ' tab-content';
19256 if (this.carousel) {
19257 cfg.cls += ' carousel slide';
19260 cls : 'carousel-inner',
19264 if(this.bullets && !Roo.isTouch){
19267 cls : 'carousel-bullets',
19271 if(this.bullets_cls){
19272 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
19279 cfg.cn[0].cn.push(bullets);
19282 if(this.showarrow){
19283 cfg.cn[0].cn.push({
19285 class : 'carousel-arrow',
19289 class : 'carousel-prev',
19293 class : 'fa fa-chevron-left'
19299 class : 'carousel-next',
19303 class : 'fa fa-chevron-right'
19316 initEvents: function()
19318 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
19319 // this.el.on("touchstart", this.onTouchStart, this);
19322 if(this.autoslide){
19325 this.slideFn = window.setInterval(function() {
19326 _this.showPanelNext();
19330 if(this.showarrow){
19331 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
19332 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
19338 // onTouchStart : function(e, el, o)
19340 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
19344 // this.showPanelNext();
19348 getChildContainer : function()
19350 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
19354 * register a Navigation item
19355 * @param {Roo.bootstrap.NavItem} the navitem to add
19357 register : function(item)
19359 this.tabs.push( item);
19360 item.navId = this.navId; // not really needed..
19365 getActivePanel : function()
19368 Roo.each(this.tabs, function(t) {
19378 getPanelByName : function(n)
19381 Roo.each(this.tabs, function(t) {
19382 if (t.tabId == n) {
19390 indexOfPanel : function(p)
19393 Roo.each(this.tabs, function(t,i) {
19394 if (t.tabId == p.tabId) {
19403 * show a specific panel
19404 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
19405 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
19407 showPanel : function (pan)
19409 if(this.transition || typeof(pan) == 'undefined'){
19410 Roo.log("waiting for the transitionend");
19414 if (typeof(pan) == 'number') {
19415 pan = this.tabs[pan];
19418 if (typeof(pan) == 'string') {
19419 pan = this.getPanelByName(pan);
19422 var cur = this.getActivePanel();
19425 Roo.log('pan or acitve pan is undefined');
19429 if (pan.tabId == this.getActivePanel().tabId) {
19433 if (false === cur.fireEvent('beforedeactivate')) {
19437 if(this.bullets > 0 && !Roo.isTouch){
19438 this.setActiveBullet(this.indexOfPanel(pan));
19441 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
19443 //class="carousel-item carousel-item-next carousel-item-left"
19445 this.transition = true;
19446 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
19447 var lr = dir == 'next' ? 'left' : 'right';
19448 pan.el.addClass(dir); // or prev
19449 pan.el.addClass('carousel-item-' + dir); // or prev
19450 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
19451 cur.el.addClass(lr); // or right
19452 pan.el.addClass(lr);
19453 cur.el.addClass('carousel-item-' +lr); // or right
19454 pan.el.addClass('carousel-item-' +lr);
19458 cur.el.on('transitionend', function() {
19459 Roo.log("trans end?");
19461 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
19462 pan.setActive(true);
19464 cur.el.removeClass([lr, 'carousel-item-' + lr]);
19465 cur.setActive(false);
19467 _this.transition = false;
19469 }, this, { single: true } );
19474 cur.setActive(false);
19475 pan.setActive(true);
19480 showPanelNext : function()
19482 var i = this.indexOfPanel(this.getActivePanel());
19484 if (i >= this.tabs.length - 1 && !this.autoslide) {
19488 if (i >= this.tabs.length - 1 && this.autoslide) {
19492 this.showPanel(this.tabs[i+1]);
19495 showPanelPrev : function()
19497 var i = this.indexOfPanel(this.getActivePanel());
19499 if (i < 1 && !this.autoslide) {
19503 if (i < 1 && this.autoslide) {
19504 i = this.tabs.length;
19507 this.showPanel(this.tabs[i-1]);
19511 addBullet: function()
19513 if(!this.bullets || Roo.isTouch){
19516 var ctr = this.el.select('.carousel-bullets',true).first();
19517 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
19518 var bullet = ctr.createChild({
19519 cls : 'bullet bullet-' + i
19520 },ctr.dom.lastChild);
19525 bullet.on('click', (function(e, el, o, ii, t){
19527 e.preventDefault();
19529 this.showPanel(ii);
19531 if(this.autoslide && this.slideFn){
19532 clearInterval(this.slideFn);
19533 this.slideFn = window.setInterval(function() {
19534 _this.showPanelNext();
19538 }).createDelegate(this, [i, bullet], true));
19543 setActiveBullet : function(i)
19549 Roo.each(this.el.select('.bullet', true).elements, function(el){
19550 el.removeClass('selected');
19553 var bullet = this.el.select('.bullet-' + i, true).first();
19559 bullet.addClass('selected');
19570 Roo.apply(Roo.bootstrap.TabGroup, {
19574 * register a Navigation Group
19575 * @param {Roo.bootstrap.NavGroup} the navgroup to add
19577 register : function(navgrp)
19579 this.groups[navgrp.navId] = navgrp;
19583 * fetch a Navigation Group based on the navigation ID
19584 * if one does not exist , it will get created.
19585 * @param {string} the navgroup to add
19586 * @returns {Roo.bootstrap.NavGroup} the navgroup
19588 get: function(navId) {
19589 if (typeof(this.groups[navId]) == 'undefined') {
19590 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
19592 return this.groups[navId] ;
19607 * @class Roo.bootstrap.TabPanel
19608 * @extends Roo.bootstrap.Component
19609 * Bootstrap TabPanel class
19610 * @cfg {Boolean} active panel active
19611 * @cfg {String} html panel content
19612 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
19613 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
19614 * @cfg {String} href click to link..
19618 * Create a new TabPanel
19619 * @param {Object} config The config object
19622 Roo.bootstrap.TabPanel = function(config){
19623 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
19627 * Fires when the active status changes
19628 * @param {Roo.bootstrap.TabPanel} this
19629 * @param {Boolean} state the new state
19634 * @event beforedeactivate
19635 * Fires before a tab is de-activated - can be used to do validation on a form.
19636 * @param {Roo.bootstrap.TabPanel} this
19637 * @return {Boolean} false if there is an error
19640 'beforedeactivate': true
19643 this.tabId = this.tabId || Roo.id();
19647 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
19655 getAutoCreate : function(){
19660 // item is needed for carousel - not sure if it has any effect otherwise
19661 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
19662 html: this.html || ''
19666 cfg.cls += ' active';
19670 cfg.tabId = this.tabId;
19678 initEvents: function()
19680 var p = this.parent();
19682 this.navId = this.navId || p.navId;
19684 if (typeof(this.navId) != 'undefined') {
19685 // not really needed.. but just in case.. parent should be a NavGroup.
19686 var tg = Roo.bootstrap.TabGroup.get(this.navId);
19690 var i = tg.tabs.length - 1;
19692 if(this.active && tg.bullets > 0 && i < tg.bullets){
19693 tg.setActiveBullet(i);
19697 this.el.on('click', this.onClick, this);
19700 this.el.on("touchstart", this.onTouchStart, this);
19701 this.el.on("touchmove", this.onTouchMove, this);
19702 this.el.on("touchend", this.onTouchEnd, this);
19707 onRender : function(ct, position)
19709 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
19712 setActive : function(state)
19714 Roo.log("panel - set active " + this.tabId + "=" + state);
19716 this.active = state;
19718 this.el.removeClass('active');
19720 } else if (!this.el.hasClass('active')) {
19721 this.el.addClass('active');
19724 this.fireEvent('changed', this, state);
19727 onClick : function(e)
19729 e.preventDefault();
19731 if(!this.href.length){
19735 window.location.href = this.href;
19744 onTouchStart : function(e)
19746 this.swiping = false;
19748 this.startX = e.browserEvent.touches[0].clientX;
19749 this.startY = e.browserEvent.touches[0].clientY;
19752 onTouchMove : function(e)
19754 this.swiping = true;
19756 this.endX = e.browserEvent.touches[0].clientX;
19757 this.endY = e.browserEvent.touches[0].clientY;
19760 onTouchEnd : function(e)
19767 var tabGroup = this.parent();
19769 if(this.endX > this.startX){ // swiping right
19770 tabGroup.showPanelPrev();
19774 if(this.startX > this.endX){ // swiping left
19775 tabGroup.showPanelNext();
19794 * @class Roo.bootstrap.DateField
19795 * @extends Roo.bootstrap.Input
19796 * Bootstrap DateField class
19797 * @cfg {Number} weekStart default 0
19798 * @cfg {String} viewMode default empty, (months|years)
19799 * @cfg {String} minViewMode default empty, (months|years)
19800 * @cfg {Number} startDate default -Infinity
19801 * @cfg {Number} endDate default Infinity
19802 * @cfg {Boolean} todayHighlight default false
19803 * @cfg {Boolean} todayBtn default false
19804 * @cfg {Boolean} calendarWeeks default false
19805 * @cfg {Object} daysOfWeekDisabled default empty
19806 * @cfg {Boolean} singleMode default false (true | false)
19808 * @cfg {Boolean} keyboardNavigation default true
19809 * @cfg {String} language default en
19812 * Create a new DateField
19813 * @param {Object} config The config object
19816 Roo.bootstrap.DateField = function(config){
19817 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
19821 * Fires when this field show.
19822 * @param {Roo.bootstrap.DateField} this
19823 * @param {Mixed} date The date value
19828 * Fires when this field hide.
19829 * @param {Roo.bootstrap.DateField} this
19830 * @param {Mixed} date The date value
19835 * Fires when select a date.
19836 * @param {Roo.bootstrap.DateField} this
19837 * @param {Mixed} date The date value
19841 * @event beforeselect
19842 * Fires when before select a date.
19843 * @param {Roo.bootstrap.DateField} this
19844 * @param {Mixed} date The date value
19846 beforeselect : true
19850 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
19853 * @cfg {String} format
19854 * The default date format string which can be overriden for localization support. The format must be
19855 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
19859 * @cfg {String} altFormats
19860 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
19861 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
19863 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
19871 todayHighlight : false,
19877 keyboardNavigation: true,
19879 calendarWeeks: false,
19881 startDate: -Infinity,
19885 daysOfWeekDisabled: [],
19889 singleMode : false,
19891 UTCDate: function()
19893 return new Date(Date.UTC.apply(Date, arguments));
19896 UTCToday: function()
19898 var today = new Date();
19899 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
19902 getDate: function() {
19903 var d = this.getUTCDate();
19904 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
19907 getUTCDate: function() {
19911 setDate: function(d) {
19912 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
19915 setUTCDate: function(d) {
19917 this.setValue(this.formatDate(this.date));
19920 onRender: function(ct, position)
19923 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
19925 this.language = this.language || 'en';
19926 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
19927 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
19929 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
19930 this.format = this.format || 'm/d/y';
19931 this.isInline = false;
19932 this.isInput = true;
19933 this.component = this.el.select('.add-on', true).first() || false;
19934 this.component = (this.component && this.component.length === 0) ? false : this.component;
19935 this.hasInput = this.component && this.inputEl().length;
19937 if (typeof(this.minViewMode === 'string')) {
19938 switch (this.minViewMode) {
19940 this.minViewMode = 1;
19943 this.minViewMode = 2;
19946 this.minViewMode = 0;
19951 if (typeof(this.viewMode === 'string')) {
19952 switch (this.viewMode) {
19965 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
19967 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
19969 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19971 this.picker().on('mousedown', this.onMousedown, this);
19972 this.picker().on('click', this.onClick, this);
19974 this.picker().addClass('datepicker-dropdown');
19976 this.startViewMode = this.viewMode;
19978 if(this.singleMode){
19979 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19980 v.setVisibilityMode(Roo.Element.DISPLAY);
19984 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19985 v.setStyle('width', '189px');
19989 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19990 if(!this.calendarWeeks){
19995 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19996 v.attr('colspan', function(i, val){
19997 return parseInt(val) + 1;
20002 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
20004 this.setStartDate(this.startDate);
20005 this.setEndDate(this.endDate);
20007 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
20014 if(this.isInline) {
20019 picker : function()
20021 return this.pickerEl;
20022 // return this.el.select('.datepicker', true).first();
20025 fillDow: function()
20027 var dowCnt = this.weekStart;
20036 if(this.calendarWeeks){
20044 while (dowCnt < this.weekStart + 7) {
20048 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
20052 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
20055 fillMonths: function()
20058 var months = this.picker().select('>.datepicker-months td', true).first();
20060 months.dom.innerHTML = '';
20066 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
20069 months.createChild(month);
20076 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;
20078 if (this.date < this.startDate) {
20079 this.viewDate = new Date(this.startDate);
20080 } else if (this.date > this.endDate) {
20081 this.viewDate = new Date(this.endDate);
20083 this.viewDate = new Date(this.date);
20091 var d = new Date(this.viewDate),
20092 year = d.getUTCFullYear(),
20093 month = d.getUTCMonth(),
20094 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
20095 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
20096 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
20097 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
20098 currentDate = this.date && this.date.valueOf(),
20099 today = this.UTCToday();
20101 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
20103 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20105 // this.picker.select('>tfoot th.today').
20106 // .text(dates[this.language].today)
20107 // .toggle(this.todayBtn !== false);
20109 this.updateNavArrows();
20112 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
20114 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
20116 prevMonth.setUTCDate(day);
20118 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
20120 var nextMonth = new Date(prevMonth);
20122 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
20124 nextMonth = nextMonth.valueOf();
20126 var fillMonths = false;
20128 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
20130 while(prevMonth.valueOf() <= nextMonth) {
20133 if (prevMonth.getUTCDay() === this.weekStart) {
20135 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
20143 if(this.calendarWeeks){
20144 // ISO 8601: First week contains first thursday.
20145 // ISO also states week starts on Monday, but we can be more abstract here.
20147 // Start of current week: based on weekstart/current date
20148 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
20149 // Thursday of this week
20150 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
20151 // First Thursday of year, year from thursday
20152 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
20153 // Calendar week: ms between thursdays, div ms per day, div 7 days
20154 calWeek = (th - yth) / 864e5 / 7 + 1;
20156 fillMonths.cn.push({
20164 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
20166 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
20169 if (this.todayHighlight &&
20170 prevMonth.getUTCFullYear() == today.getFullYear() &&
20171 prevMonth.getUTCMonth() == today.getMonth() &&
20172 prevMonth.getUTCDate() == today.getDate()) {
20173 clsName += ' today';
20176 if (currentDate && prevMonth.valueOf() === currentDate) {
20177 clsName += ' active';
20180 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
20181 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
20182 clsName += ' disabled';
20185 fillMonths.cn.push({
20187 cls: 'day ' + clsName,
20188 html: prevMonth.getDate()
20191 prevMonth.setDate(prevMonth.getDate()+1);
20194 var currentYear = this.date && this.date.getUTCFullYear();
20195 var currentMonth = this.date && this.date.getUTCMonth();
20197 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
20199 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
20200 v.removeClass('active');
20202 if(currentYear === year && k === currentMonth){
20203 v.addClass('active');
20206 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
20207 v.addClass('disabled');
20213 year = parseInt(year/10, 10) * 10;
20215 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
20217 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
20220 for (var i = -1; i < 11; i++) {
20221 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
20223 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
20231 showMode: function(dir)
20234 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
20237 Roo.each(this.picker().select('>div',true).elements, function(v){
20238 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20241 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
20246 if(this.isInline) {
20250 this.picker().removeClass(['bottom', 'top']);
20252 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20254 * place to the top of element!
20258 this.picker().addClass('top');
20259 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20264 this.picker().addClass('bottom');
20266 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20269 parseDate : function(value)
20271 if(!value || value instanceof Date){
20274 var v = Date.parseDate(value, this.format);
20275 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
20276 v = Date.parseDate(value, 'Y-m-d');
20278 if(!v && this.altFormats){
20279 if(!this.altFormatsArray){
20280 this.altFormatsArray = this.altFormats.split("|");
20282 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
20283 v = Date.parseDate(value, this.altFormatsArray[i]);
20289 formatDate : function(date, fmt)
20291 return (!date || !(date instanceof Date)) ?
20292 date : date.dateFormat(fmt || this.format);
20295 onFocus : function()
20297 Roo.bootstrap.DateField.superclass.onFocus.call(this);
20301 onBlur : function()
20303 Roo.bootstrap.DateField.superclass.onBlur.call(this);
20305 var d = this.inputEl().getValue();
20312 showPopup : function()
20314 this.picker().show();
20318 this.fireEvent('showpopup', this, this.date);
20321 hidePopup : function()
20323 if(this.isInline) {
20326 this.picker().hide();
20327 this.viewMode = this.startViewMode;
20330 this.fireEvent('hidepopup', this, this.date);
20334 onMousedown: function(e)
20336 e.stopPropagation();
20337 e.preventDefault();
20342 Roo.bootstrap.DateField.superclass.keyup.call(this);
20346 setValue: function(v)
20348 if(this.fireEvent('beforeselect', this, v) !== false){
20349 var d = new Date(this.parseDate(v) ).clearTime();
20351 if(isNaN(d.getTime())){
20352 this.date = this.viewDate = '';
20353 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
20357 v = this.formatDate(d);
20359 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
20361 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
20365 this.fireEvent('select', this, this.date);
20369 getValue: function()
20371 return this.formatDate(this.date);
20374 fireKey: function(e)
20376 if (!this.picker().isVisible()){
20377 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20383 var dateChanged = false,
20385 newDate, newViewDate;
20390 e.preventDefault();
20394 if (!this.keyboardNavigation) {
20397 dir = e.keyCode == 37 ? -1 : 1;
20400 newDate = this.moveYear(this.date, dir);
20401 newViewDate = this.moveYear(this.viewDate, dir);
20402 } else if (e.shiftKey){
20403 newDate = this.moveMonth(this.date, dir);
20404 newViewDate = this.moveMonth(this.viewDate, dir);
20406 newDate = new Date(this.date);
20407 newDate.setUTCDate(this.date.getUTCDate() + dir);
20408 newViewDate = new Date(this.viewDate);
20409 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
20411 if (this.dateWithinRange(newDate)){
20412 this.date = newDate;
20413 this.viewDate = newViewDate;
20414 this.setValue(this.formatDate(this.date));
20416 e.preventDefault();
20417 dateChanged = true;
20422 if (!this.keyboardNavigation) {
20425 dir = e.keyCode == 38 ? -1 : 1;
20427 newDate = this.moveYear(this.date, dir);
20428 newViewDate = this.moveYear(this.viewDate, dir);
20429 } else if (e.shiftKey){
20430 newDate = this.moveMonth(this.date, dir);
20431 newViewDate = this.moveMonth(this.viewDate, dir);
20433 newDate = new Date(this.date);
20434 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
20435 newViewDate = new Date(this.viewDate);
20436 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
20438 if (this.dateWithinRange(newDate)){
20439 this.date = newDate;
20440 this.viewDate = newViewDate;
20441 this.setValue(this.formatDate(this.date));
20443 e.preventDefault();
20444 dateChanged = true;
20448 this.setValue(this.formatDate(this.date));
20450 e.preventDefault();
20453 this.setValue(this.formatDate(this.date));
20467 onClick: function(e)
20469 e.stopPropagation();
20470 e.preventDefault();
20472 var target = e.getTarget();
20474 if(target.nodeName.toLowerCase() === 'i'){
20475 target = Roo.get(target).dom.parentNode;
20478 var nodeName = target.nodeName;
20479 var className = target.className;
20480 var html = target.innerHTML;
20481 //Roo.log(nodeName);
20483 switch(nodeName.toLowerCase()) {
20485 switch(className) {
20491 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
20492 switch(this.viewMode){
20494 this.viewDate = this.moveMonth(this.viewDate, dir);
20498 this.viewDate = this.moveYear(this.viewDate, dir);
20504 var date = new Date();
20505 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
20507 this.setValue(this.formatDate(this.date));
20514 if (className.indexOf('disabled') < 0) {
20515 this.viewDate.setUTCDate(1);
20516 if (className.indexOf('month') > -1) {
20517 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
20519 var year = parseInt(html, 10) || 0;
20520 this.viewDate.setUTCFullYear(year);
20524 if(this.singleMode){
20525 this.setValue(this.formatDate(this.viewDate));
20536 //Roo.log(className);
20537 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
20538 var day = parseInt(html, 10) || 1;
20539 var year = this.viewDate.getUTCFullYear(),
20540 month = this.viewDate.getUTCMonth();
20542 if (className.indexOf('old') > -1) {
20549 } else if (className.indexOf('new') > -1) {
20557 //Roo.log([year,month,day]);
20558 this.date = this.UTCDate(year, month, day,0,0,0,0);
20559 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
20561 //Roo.log(this.formatDate(this.date));
20562 this.setValue(this.formatDate(this.date));
20569 setStartDate: function(startDate)
20571 this.startDate = startDate || -Infinity;
20572 if (this.startDate !== -Infinity) {
20573 this.startDate = this.parseDate(this.startDate);
20576 this.updateNavArrows();
20579 setEndDate: function(endDate)
20581 this.endDate = endDate || Infinity;
20582 if (this.endDate !== Infinity) {
20583 this.endDate = this.parseDate(this.endDate);
20586 this.updateNavArrows();
20589 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
20591 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
20592 if (typeof(this.daysOfWeekDisabled) !== 'object') {
20593 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
20595 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
20596 return parseInt(d, 10);
20599 this.updateNavArrows();
20602 updateNavArrows: function()
20604 if(this.singleMode){
20608 var d = new Date(this.viewDate),
20609 year = d.getUTCFullYear(),
20610 month = d.getUTCMonth();
20612 Roo.each(this.picker().select('.prev', true).elements, function(v){
20614 switch (this.viewMode) {
20617 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
20623 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
20630 Roo.each(this.picker().select('.next', true).elements, function(v){
20632 switch (this.viewMode) {
20635 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
20641 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
20649 moveMonth: function(date, dir)
20654 var new_date = new Date(date.valueOf()),
20655 day = new_date.getUTCDate(),
20656 month = new_date.getUTCMonth(),
20657 mag = Math.abs(dir),
20659 dir = dir > 0 ? 1 : -1;
20662 // If going back one month, make sure month is not current month
20663 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
20665 return new_date.getUTCMonth() == month;
20667 // If going forward one month, make sure month is as expected
20668 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
20670 return new_date.getUTCMonth() != new_month;
20672 new_month = month + dir;
20673 new_date.setUTCMonth(new_month);
20674 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
20675 if (new_month < 0 || new_month > 11) {
20676 new_month = (new_month + 12) % 12;
20679 // For magnitudes >1, move one month at a time...
20680 for (var i=0; i<mag; i++) {
20681 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
20682 new_date = this.moveMonth(new_date, dir);
20684 // ...then reset the day, keeping it in the new month
20685 new_month = new_date.getUTCMonth();
20686 new_date.setUTCDate(day);
20688 return new_month != new_date.getUTCMonth();
20691 // Common date-resetting loop -- if date is beyond end of month, make it
20694 new_date.setUTCDate(--day);
20695 new_date.setUTCMonth(new_month);
20700 moveYear: function(date, dir)
20702 return this.moveMonth(date, dir*12);
20705 dateWithinRange: function(date)
20707 return date >= this.startDate && date <= this.endDate;
20713 this.picker().remove();
20716 validateValue : function(value)
20718 if(this.getVisibilityEl().hasClass('hidden')){
20722 if(value.length < 1) {
20723 if(this.allowBlank){
20729 if(value.length < this.minLength){
20732 if(value.length > this.maxLength){
20736 var vt = Roo.form.VTypes;
20737 if(!vt[this.vtype](value, this)){
20741 if(typeof this.validator == "function"){
20742 var msg = this.validator(value);
20748 if(this.regex && !this.regex.test(value)){
20752 if(typeof(this.parseDate(value)) == 'undefined'){
20756 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
20760 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
20770 this.date = this.viewDate = '';
20772 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
20777 Roo.apply(Roo.bootstrap.DateField, {
20788 html: '<i class="fa fa-arrow-left"/>'
20798 html: '<i class="fa fa-arrow-right"/>'
20840 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
20841 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
20842 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
20843 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20844 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
20857 navFnc: 'FullYear',
20862 navFnc: 'FullYear',
20867 Roo.apply(Roo.bootstrap.DateField, {
20871 cls: 'datepicker dropdown-menu roo-dynamic',
20875 cls: 'datepicker-days',
20879 cls: 'table-condensed',
20881 Roo.bootstrap.DateField.head,
20885 Roo.bootstrap.DateField.footer
20892 cls: 'datepicker-months',
20896 cls: 'table-condensed',
20898 Roo.bootstrap.DateField.head,
20899 Roo.bootstrap.DateField.content,
20900 Roo.bootstrap.DateField.footer
20907 cls: 'datepicker-years',
20911 cls: 'table-condensed',
20913 Roo.bootstrap.DateField.head,
20914 Roo.bootstrap.DateField.content,
20915 Roo.bootstrap.DateField.footer
20934 * @class Roo.bootstrap.TimeField
20935 * @extends Roo.bootstrap.Input
20936 * Bootstrap DateField class
20940 * Create a new TimeField
20941 * @param {Object} config The config object
20944 Roo.bootstrap.TimeField = function(config){
20945 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
20949 * Fires when this field show.
20950 * @param {Roo.bootstrap.DateField} thisthis
20951 * @param {Mixed} date The date value
20956 * Fires when this field hide.
20957 * @param {Roo.bootstrap.DateField} this
20958 * @param {Mixed} date The date value
20963 * Fires when select a date.
20964 * @param {Roo.bootstrap.DateField} this
20965 * @param {Mixed} date The date value
20971 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20974 * @cfg {String} format
20975 * The default time format string which can be overriden for localization support. The format must be
20976 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20980 onRender: function(ct, position)
20983 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20985 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20987 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20989 this.pop = this.picker().select('>.datepicker-time',true).first();
20990 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20992 this.picker().on('mousedown', this.onMousedown, this);
20993 this.picker().on('click', this.onClick, this);
20995 this.picker().addClass('datepicker-dropdown');
21000 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
21001 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
21002 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
21003 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
21004 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
21005 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
21009 fireKey: function(e){
21010 if (!this.picker().isVisible()){
21011 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21017 e.preventDefault();
21025 this.onTogglePeriod();
21028 this.onIncrementMinutes();
21031 this.onDecrementMinutes();
21040 onClick: function(e) {
21041 e.stopPropagation();
21042 e.preventDefault();
21045 picker : function()
21047 return this.el.select('.datepicker', true).first();
21050 fillTime: function()
21052 var time = this.pop.select('tbody', true).first();
21054 time.dom.innerHTML = '';
21069 cls: 'hours-up glyphicon glyphicon-chevron-up'
21089 cls: 'minutes-up glyphicon glyphicon-chevron-up'
21110 cls: 'timepicker-hour',
21125 cls: 'timepicker-minute',
21140 cls: 'btn btn-primary period',
21162 cls: 'hours-down glyphicon glyphicon-chevron-down'
21182 cls: 'minutes-down glyphicon glyphicon-chevron-down'
21200 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
21207 var hours = this.time.getHours();
21208 var minutes = this.time.getMinutes();
21221 hours = hours - 12;
21225 hours = '0' + hours;
21229 minutes = '0' + minutes;
21232 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
21233 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
21234 this.pop.select('button', true).first().dom.innerHTML = period;
21240 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
21242 var cls = ['bottom'];
21244 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
21251 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
21256 this.picker().addClass(cls.join('-'));
21260 Roo.each(cls, function(c){
21262 _this.picker().setTop(_this.inputEl().getHeight());
21266 _this.picker().setTop(0 - _this.picker().getHeight());
21271 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
21275 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
21282 onFocus : function()
21284 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
21288 onBlur : function()
21290 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
21296 this.picker().show();
21301 this.fireEvent('show', this, this.date);
21306 this.picker().hide();
21309 this.fireEvent('hide', this, this.date);
21312 setTime : function()
21315 this.setValue(this.time.format(this.format));
21317 this.fireEvent('select', this, this.date);
21322 onMousedown: function(e){
21323 e.stopPropagation();
21324 e.preventDefault();
21327 onIncrementHours: function()
21329 Roo.log('onIncrementHours');
21330 this.time = this.time.add(Date.HOUR, 1);
21335 onDecrementHours: function()
21337 Roo.log('onDecrementHours');
21338 this.time = this.time.add(Date.HOUR, -1);
21342 onIncrementMinutes: function()
21344 Roo.log('onIncrementMinutes');
21345 this.time = this.time.add(Date.MINUTE, 1);
21349 onDecrementMinutes: function()
21351 Roo.log('onDecrementMinutes');
21352 this.time = this.time.add(Date.MINUTE, -1);
21356 onTogglePeriod: function()
21358 Roo.log('onTogglePeriod');
21359 this.time = this.time.add(Date.HOUR, 12);
21366 Roo.apply(Roo.bootstrap.TimeField, {
21396 cls: 'btn btn-info ok',
21408 Roo.apply(Roo.bootstrap.TimeField, {
21412 cls: 'datepicker dropdown-menu',
21416 cls: 'datepicker-time',
21420 cls: 'table-condensed',
21422 Roo.bootstrap.TimeField.content,
21423 Roo.bootstrap.TimeField.footer
21442 * @class Roo.bootstrap.MonthField
21443 * @extends Roo.bootstrap.Input
21444 * Bootstrap MonthField class
21446 * @cfg {String} language default en
21449 * Create a new MonthField
21450 * @param {Object} config The config object
21453 Roo.bootstrap.MonthField = function(config){
21454 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
21459 * Fires when this field show.
21460 * @param {Roo.bootstrap.MonthField} this
21461 * @param {Mixed} date The date value
21466 * Fires when this field hide.
21467 * @param {Roo.bootstrap.MonthField} this
21468 * @param {Mixed} date The date value
21473 * Fires when select a date.
21474 * @param {Roo.bootstrap.MonthField} this
21475 * @param {String} oldvalue The old value
21476 * @param {String} newvalue The new value
21482 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
21484 onRender: function(ct, position)
21487 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
21489 this.language = this.language || 'en';
21490 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
21491 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
21493 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
21494 this.isInline = false;
21495 this.isInput = true;
21496 this.component = this.el.select('.add-on', true).first() || false;
21497 this.component = (this.component && this.component.length === 0) ? false : this.component;
21498 this.hasInput = this.component && this.inputEL().length;
21500 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
21502 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21504 this.picker().on('mousedown', this.onMousedown, this);
21505 this.picker().on('click', this.onClick, this);
21507 this.picker().addClass('datepicker-dropdown');
21509 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
21510 v.setStyle('width', '189px');
21517 if(this.isInline) {
21523 setValue: function(v, suppressEvent)
21525 var o = this.getValue();
21527 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
21531 if(suppressEvent !== true){
21532 this.fireEvent('select', this, o, v);
21537 getValue: function()
21542 onClick: function(e)
21544 e.stopPropagation();
21545 e.preventDefault();
21547 var target = e.getTarget();
21549 if(target.nodeName.toLowerCase() === 'i'){
21550 target = Roo.get(target).dom.parentNode;
21553 var nodeName = target.nodeName;
21554 var className = target.className;
21555 var html = target.innerHTML;
21557 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
21561 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
21563 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21569 picker : function()
21571 return this.pickerEl;
21574 fillMonths: function()
21577 var months = this.picker().select('>.datepicker-months td', true).first();
21579 months.dom.innerHTML = '';
21585 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
21588 months.createChild(month);
21597 if(typeof(this.vIndex) == 'undefined' && this.value.length){
21598 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
21601 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
21602 e.removeClass('active');
21604 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
21605 e.addClass('active');
21612 if(this.isInline) {
21616 this.picker().removeClass(['bottom', 'top']);
21618 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
21620 * place to the top of element!
21624 this.picker().addClass('top');
21625 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
21630 this.picker().addClass('bottom');
21632 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
21635 onFocus : function()
21637 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
21641 onBlur : function()
21643 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
21645 var d = this.inputEl().getValue();
21654 this.picker().show();
21655 this.picker().select('>.datepicker-months', true).first().show();
21659 this.fireEvent('show', this, this.date);
21664 if(this.isInline) {
21667 this.picker().hide();
21668 this.fireEvent('hide', this, this.date);
21672 onMousedown: function(e)
21674 e.stopPropagation();
21675 e.preventDefault();
21680 Roo.bootstrap.MonthField.superclass.keyup.call(this);
21684 fireKey: function(e)
21686 if (!this.picker().isVisible()){
21687 if (e.keyCode == 27) {// allow escape to hide and re-show picker
21698 e.preventDefault();
21702 dir = e.keyCode == 37 ? -1 : 1;
21704 this.vIndex = this.vIndex + dir;
21706 if(this.vIndex < 0){
21710 if(this.vIndex > 11){
21714 if(isNaN(this.vIndex)){
21718 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21724 dir = e.keyCode == 38 ? -1 : 1;
21726 this.vIndex = this.vIndex + dir * 4;
21728 if(this.vIndex < 0){
21732 if(this.vIndex > 11){
21736 if(isNaN(this.vIndex)){
21740 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21745 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
21746 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21750 e.preventDefault();
21753 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
21754 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
21770 this.picker().remove();
21775 Roo.apply(Roo.bootstrap.MonthField, {
21794 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
21795 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
21800 Roo.apply(Roo.bootstrap.MonthField, {
21804 cls: 'datepicker dropdown-menu roo-dynamic',
21808 cls: 'datepicker-months',
21812 cls: 'table-condensed',
21814 Roo.bootstrap.DateField.content
21834 * @class Roo.bootstrap.CheckBox
21835 * @extends Roo.bootstrap.Input
21836 * Bootstrap CheckBox class
21838 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
21839 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
21840 * @cfg {String} boxLabel The text that appears beside the checkbox
21841 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
21842 * @cfg {Boolean} checked initnal the element
21843 * @cfg {Boolean} inline inline the element (default false)
21844 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
21845 * @cfg {String} tooltip label tooltip
21848 * Create a new CheckBox
21849 * @param {Object} config The config object
21852 Roo.bootstrap.CheckBox = function(config){
21853 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
21858 * Fires when the element is checked or unchecked.
21859 * @param {Roo.bootstrap.CheckBox} this This input
21860 * @param {Boolean} checked The new checked value
21865 * Fires when the element is click.
21866 * @param {Roo.bootstrap.CheckBox} this This input
21873 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
21875 inputType: 'checkbox',
21884 // checkbox success does not make any sense really..
21889 getAutoCreate : function()
21891 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
21897 cfg.cls = 'form-group form-check ' + this.inputType; //input-group
21900 cfg.cls += ' ' + this.inputType + '-inline form-check-inline';
21906 type : this.inputType,
21907 value : this.inputValue,
21908 cls : 'roo-' + this.inputType, //'form-box',
21909 placeholder : this.placeholder || ''
21913 if(this.inputType != 'radio'){
21917 cls : 'roo-hidden-value',
21918 value : this.checked ? this.inputValue : this.valueOff
21923 if (this.weight) { // Validity check?
21924 cfg.cls += " " + this.inputType + "-" + this.weight;
21927 if (this.disabled) {
21928 input.disabled=true;
21932 input.checked = this.checked;
21937 input.name = this.name;
21939 if(this.inputType != 'radio'){
21940 hidden.name = this.name;
21941 input.name = '_hidden_' + this.name;
21946 input.cls += ' input-' + this.size;
21951 ['xs','sm','md','lg'].map(function(size){
21952 if (settings[size]) {
21953 cfg.cls += ' col-' + size + '-' + settings[size];
21957 var inputblock = input;
21959 if (this.before || this.after) {
21962 cls : 'input-group',
21967 inputblock.cn.push({
21969 cls : 'input-group-addon',
21974 inputblock.cn.push(input);
21976 if(this.inputType != 'radio'){
21977 inputblock.cn.push(hidden);
21981 inputblock.cn.push({
21983 cls : 'input-group-addon',
21989 var boxLabelCfg = false;
21995 //'for': id, // box label is handled by onclick - so no for...
21997 html: this.boxLabel
22000 boxLabelCfg.tooltip = this.tooltip;
22006 if (align ==='left' && this.fieldLabel.length) {
22007 // Roo.log("left and has label");
22012 cls : 'control-label',
22013 html : this.fieldLabel
22024 cfg.cn[1].cn.push(boxLabelCfg);
22027 if(this.labelWidth > 12){
22028 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
22031 if(this.labelWidth < 13 && this.labelmd == 0){
22032 this.labelmd = this.labelWidth;
22035 if(this.labellg > 0){
22036 cfg.cn[0].cls += ' col-lg-' + this.labellg;
22037 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
22040 if(this.labelmd > 0){
22041 cfg.cn[0].cls += ' col-md-' + this.labelmd;
22042 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
22045 if(this.labelsm > 0){
22046 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
22047 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
22050 if(this.labelxs > 0){
22051 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
22052 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
22055 } else if ( this.fieldLabel.length) {
22056 // Roo.log(" label");
22060 tag: this.boxLabel ? 'span' : 'label',
22062 cls: 'control-label box-input-label',
22063 //cls : 'input-group-addon',
22064 html : this.fieldLabel
22071 cfg.cn.push(boxLabelCfg);
22076 // Roo.log(" no label && no align");
22077 cfg.cn = [ inputblock ] ;
22079 cfg.cn.push(boxLabelCfg);
22087 if(this.inputType != 'radio'){
22088 cfg.cn.push(hidden);
22096 * return the real input element.
22098 inputEl: function ()
22100 return this.el.select('input.roo-' + this.inputType,true).first();
22102 hiddenEl: function ()
22104 return this.el.select('input.roo-hidden-value',true).first();
22107 labelEl: function()
22109 return this.el.select('label.control-label',true).first();
22111 /* depricated... */
22115 return this.labelEl();
22118 boxLabelEl: function()
22120 return this.el.select('label.box-label',true).first();
22123 initEvents : function()
22125 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
22127 this.inputEl().on('click', this.onClick, this);
22129 if (this.boxLabel) {
22130 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
22133 this.startValue = this.getValue();
22136 Roo.bootstrap.CheckBox.register(this);
22140 onClick : function(e)
22142 if(this.fireEvent('click', this, e) !== false){
22143 this.setChecked(!this.checked);
22148 setChecked : function(state,suppressEvent)
22150 this.startValue = this.getValue();
22152 if(this.inputType == 'radio'){
22154 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22155 e.dom.checked = false;
22158 this.inputEl().dom.checked = true;
22160 this.inputEl().dom.value = this.inputValue;
22162 if(suppressEvent !== true){
22163 this.fireEvent('check', this, true);
22171 this.checked = state;
22173 this.inputEl().dom.checked = state;
22176 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
22178 if(suppressEvent !== true){
22179 this.fireEvent('check', this, state);
22185 getValue : function()
22187 if(this.inputType == 'radio'){
22188 return this.getGroupValue();
22191 return this.hiddenEl().dom.value;
22195 getGroupValue : function()
22197 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
22201 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
22204 setValue : function(v,suppressEvent)
22206 if(this.inputType == 'radio'){
22207 this.setGroupValue(v, suppressEvent);
22211 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
22216 setGroupValue : function(v, suppressEvent)
22218 this.startValue = this.getValue();
22220 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22221 e.dom.checked = false;
22223 if(e.dom.value == v){
22224 e.dom.checked = true;
22228 if(suppressEvent !== true){
22229 this.fireEvent('check', this, true);
22237 validate : function()
22239 if(this.getVisibilityEl().hasClass('hidden')){
22245 (this.inputType == 'radio' && this.validateRadio()) ||
22246 (this.inputType == 'checkbox' && this.validateCheckbox())
22252 this.markInvalid();
22256 validateRadio : function()
22258 if(this.getVisibilityEl().hasClass('hidden')){
22262 if(this.allowBlank){
22268 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22269 if(!e.dom.checked){
22281 validateCheckbox : function()
22284 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
22285 //return (this.getValue() == this.inputValue) ? true : false;
22288 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22296 for(var i in group){
22297 if(group[i].el.isVisible(true)){
22305 for(var i in group){
22310 r = (group[i].getValue() == group[i].inputValue) ? true : false;
22317 * Mark this field as valid
22319 markValid : function()
22323 this.fireEvent('valid', this);
22325 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22328 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
22335 if(this.inputType == 'radio'){
22336 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22337 var fg = e.findParent('.form-group', false, true);
22338 if (Roo.bootstrap.version == 3) {
22339 fg.removeClass([_this.invalidClass, _this.validClass]);
22340 fg.addClass(_this.validClass);
22342 fg.removeClass(['is-valid', 'is-invalid']);
22343 fg.addClass('is-valid');
22351 var fg = this.el.findParent('.form-group', false, true);
22352 if (Roo.bootstrap.version == 3) {
22353 fg.removeClass([this.invalidClass, this.validClass]);
22354 fg.addClass(this.validClass);
22356 fg.removeClass(['is-valid', 'is-invalid']);
22357 fg.addClass('is-valid');
22362 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22368 for(var i in group){
22369 var fg = group[i].el.findParent('.form-group', false, true);
22370 if (Roo.bootstrap.version == 3) {
22371 fg.removeClass([this.invalidClass, this.validClass]);
22372 fg.addClass(this.validClass);
22374 fg.removeClass(['is-valid', 'is-invalid']);
22375 fg.addClass('is-valid');
22381 * Mark this field as invalid
22382 * @param {String} msg The validation message
22384 markInvalid : function(msg)
22386 if(this.allowBlank){
22392 this.fireEvent('invalid', this, msg);
22394 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22397 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
22401 label.markInvalid();
22404 if(this.inputType == 'radio'){
22406 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22407 var fg = e.findParent('.form-group', false, true);
22408 if (Roo.bootstrap.version == 3) {
22409 fg.removeClass([_this.invalidClass, _this.validClass]);
22410 fg.addClass(_this.invalidClass);
22412 fg.removeClass(['is-invalid', 'is-valid']);
22413 fg.addClass('is-invalid');
22421 var fg = this.el.findParent('.form-group', false, true);
22422 if (Roo.bootstrap.version == 3) {
22423 fg.removeClass([_this.invalidClass, _this.validClass]);
22424 fg.addClass(_this.invalidClass);
22426 fg.removeClass(['is-invalid', 'is-valid']);
22427 fg.addClass('is-invalid');
22432 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22438 for(var i in group){
22439 var fg = group[i].el.findParent('.form-group', false, true);
22440 if (Roo.bootstrap.version == 3) {
22441 fg.removeClass([_this.invalidClass, _this.validClass]);
22442 fg.addClass(_this.invalidClass);
22444 fg.removeClass(['is-invalid', 'is-valid']);
22445 fg.addClass('is-invalid');
22451 clearInvalid : function()
22453 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
22455 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
22457 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22459 if (label && label.iconEl) {
22460 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
22461 label.iconEl.removeClass(['is-invalid', 'is-valid']);
22465 disable : function()
22467 if(this.inputType != 'radio'){
22468 Roo.bootstrap.CheckBox.superclass.disable.call(this);
22475 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22476 _this.getActionEl().addClass(this.disabledClass);
22477 e.dom.disabled = true;
22481 this.disabled = true;
22482 this.fireEvent("disable", this);
22486 enable : function()
22488 if(this.inputType != 'radio'){
22489 Roo.bootstrap.CheckBox.superclass.enable.call(this);
22496 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22497 _this.getActionEl().removeClass(this.disabledClass);
22498 e.dom.disabled = false;
22502 this.disabled = false;
22503 this.fireEvent("enable", this);
22507 setBoxLabel : function(v)
22512 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
22518 Roo.apply(Roo.bootstrap.CheckBox, {
22523 * register a CheckBox Group
22524 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
22526 register : function(checkbox)
22528 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
22529 this.groups[checkbox.groupId] = {};
22532 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
22536 this.groups[checkbox.groupId][checkbox.name] = checkbox;
22540 * fetch a CheckBox Group based on the group ID
22541 * @param {string} the group ID
22542 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
22544 get: function(groupId) {
22545 if (typeof(this.groups[groupId]) == 'undefined') {
22549 return this.groups[groupId] ;
22562 * @class Roo.bootstrap.Radio
22563 * @extends Roo.bootstrap.Component
22564 * Bootstrap Radio class
22565 * @cfg {String} boxLabel - the label associated
22566 * @cfg {String} value - the value of radio
22569 * Create a new Radio
22570 * @param {Object} config The config object
22572 Roo.bootstrap.Radio = function(config){
22573 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
22577 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
22583 getAutoCreate : function()
22587 cls : 'form-group radio',
22592 html : this.boxLabel
22600 initEvents : function()
22602 this.parent().register(this);
22604 this.el.on('click', this.onClick, this);
22608 onClick : function(e)
22610 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
22611 this.setChecked(true);
22615 setChecked : function(state, suppressEvent)
22617 this.parent().setValue(this.value, suppressEvent);
22621 setBoxLabel : function(v)
22626 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
22641 * @class Roo.bootstrap.SecurePass
22642 * @extends Roo.bootstrap.Input
22643 * Bootstrap SecurePass class
22647 * Create a new SecurePass
22648 * @param {Object} config The config object
22651 Roo.bootstrap.SecurePass = function (config) {
22652 // these go here, so the translation tool can replace them..
22654 PwdEmpty: "Please type a password, and then retype it to confirm.",
22655 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
22656 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
22657 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
22658 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
22659 FNInPwd: "Your password can't contain your first name. Please type a different password.",
22660 LNInPwd: "Your password can't contain your last name. Please type a different password.",
22661 TooWeak: "Your password is Too Weak."
22663 this.meterLabel = "Password strength:";
22664 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
22665 this.meterClass = [
22666 "roo-password-meter-tooweak",
22667 "roo-password-meter-weak",
22668 "roo-password-meter-medium",
22669 "roo-password-meter-strong",
22670 "roo-password-meter-grey"
22675 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
22678 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
22680 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
22682 * PwdEmpty: "Please type a password, and then retype it to confirm.",
22683 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
22684 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
22685 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
22686 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
22687 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
22688 * LNInPwd: "Your password can't contain your last name. Please type a different password."
22698 * @cfg {String/Object} Label for the strength meter (defaults to
22699 * 'Password strength:')
22704 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
22705 * ['Weak', 'Medium', 'Strong'])
22708 pwdStrengths: false,
22721 initEvents: function ()
22723 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
22725 if (this.el.is('input[type=password]') && Roo.isSafari) {
22726 this.el.on('keydown', this.SafariOnKeyDown, this);
22729 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
22732 onRender: function (ct, position)
22734 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
22735 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
22736 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
22738 this.trigger.createChild({
22743 cls: 'roo-password-meter-grey col-xs-12',
22746 //width: this.meterWidth + 'px'
22750 cls: 'roo-password-meter-text'
22756 if (this.hideTrigger) {
22757 this.trigger.setDisplayed(false);
22759 this.setSize(this.width || '', this.height || '');
22762 onDestroy: function ()
22764 if (this.trigger) {
22765 this.trigger.removeAllListeners();
22766 this.trigger.remove();
22769 this.wrap.remove();
22771 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
22774 checkStrength: function ()
22776 var pwd = this.inputEl().getValue();
22777 if (pwd == this._lastPwd) {
22782 if (this.ClientSideStrongPassword(pwd)) {
22784 } else if (this.ClientSideMediumPassword(pwd)) {
22786 } else if (this.ClientSideWeakPassword(pwd)) {
22792 Roo.log('strength1: ' + strength);
22794 //var pm = this.trigger.child('div/div/div').dom;
22795 var pm = this.trigger.child('div/div');
22796 pm.removeClass(this.meterClass);
22797 pm.addClass(this.meterClass[strength]);
22800 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22802 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
22804 this._lastPwd = pwd;
22808 Roo.bootstrap.SecurePass.superclass.reset.call(this);
22810 this._lastPwd = '';
22812 var pm = this.trigger.child('div/div');
22813 pm.removeClass(this.meterClass);
22814 pm.addClass('roo-password-meter-grey');
22817 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22820 this.inputEl().dom.type='password';
22823 validateValue: function (value)
22826 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
22829 if (value.length == 0) {
22830 if (this.allowBlank) {
22831 this.clearInvalid();
22835 this.markInvalid(this.errors.PwdEmpty);
22836 this.errorMsg = this.errors.PwdEmpty;
22844 if ('[\x21-\x7e]*'.match(value)) {
22845 this.markInvalid(this.errors.PwdBadChar);
22846 this.errorMsg = this.errors.PwdBadChar;
22849 if (value.length < 6) {
22850 this.markInvalid(this.errors.PwdShort);
22851 this.errorMsg = this.errors.PwdShort;
22854 if (value.length > 16) {
22855 this.markInvalid(this.errors.PwdLong);
22856 this.errorMsg = this.errors.PwdLong;
22860 if (this.ClientSideStrongPassword(value)) {
22862 } else if (this.ClientSideMediumPassword(value)) {
22864 } else if (this.ClientSideWeakPassword(value)) {
22871 if (strength < 2) {
22872 //this.markInvalid(this.errors.TooWeak);
22873 this.errorMsg = this.errors.TooWeak;
22878 console.log('strength2: ' + strength);
22880 //var pm = this.trigger.child('div/div/div').dom;
22882 var pm = this.trigger.child('div/div');
22883 pm.removeClass(this.meterClass);
22884 pm.addClass(this.meterClass[strength]);
22886 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
22888 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
22890 this.errorMsg = '';
22894 CharacterSetChecks: function (type)
22897 this.fResult = false;
22900 isctype: function (character, type)
22903 case this.kCapitalLetter:
22904 if (character >= 'A' && character <= 'Z') {
22909 case this.kSmallLetter:
22910 if (character >= 'a' && character <= 'z') {
22916 if (character >= '0' && character <= '9') {
22921 case this.kPunctuation:
22922 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
22933 IsLongEnough: function (pwd, size)
22935 return !(pwd == null || isNaN(size) || pwd.length < size);
22938 SpansEnoughCharacterSets: function (word, nb)
22940 if (!this.IsLongEnough(word, nb))
22945 var characterSetChecks = new Array(
22946 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
22947 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
22950 for (var index = 0; index < word.length; ++index) {
22951 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
22952 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
22953 characterSetChecks[nCharSet].fResult = true;
22960 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
22961 if (characterSetChecks[nCharSet].fResult) {
22966 if (nCharSets < nb) {
22972 ClientSideStrongPassword: function (pwd)
22974 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
22977 ClientSideMediumPassword: function (pwd)
22979 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22982 ClientSideWeakPassword: function (pwd)
22984 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22987 })//<script type="text/javascript">
22990 * Based Ext JS Library 1.1.1
22991 * Copyright(c) 2006-2007, Ext JS, LLC.
22997 * @class Roo.HtmlEditorCore
22998 * @extends Roo.Component
22999 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
23001 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23004 Roo.HtmlEditorCore = function(config){
23007 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
23012 * @event initialize
23013 * Fires when the editor is fully initialized (including the iframe)
23014 * @param {Roo.HtmlEditorCore} this
23019 * Fires when the editor is first receives the focus. Any insertion must wait
23020 * until after this event.
23021 * @param {Roo.HtmlEditorCore} this
23025 * @event beforesync
23026 * Fires before the textarea is updated with content from the editor iframe. Return false
23027 * to cancel the sync.
23028 * @param {Roo.HtmlEditorCore} this
23029 * @param {String} html
23033 * @event beforepush
23034 * Fires before the iframe editor is updated with content from the textarea. Return false
23035 * to cancel the push.
23036 * @param {Roo.HtmlEditorCore} this
23037 * @param {String} html
23042 * Fires when the textarea is updated with content from the editor iframe.
23043 * @param {Roo.HtmlEditorCore} this
23044 * @param {String} html
23049 * Fires when the iframe editor is updated with content from the textarea.
23050 * @param {Roo.HtmlEditorCore} this
23051 * @param {String} html
23056 * @event editorevent
23057 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23058 * @param {Roo.HtmlEditorCore} this
23064 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
23066 // defaults : white / black...
23067 this.applyBlacklists();
23074 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
23078 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
23084 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23089 * @cfg {Number} height (in pixels)
23093 * @cfg {Number} width (in pixels)
23098 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23101 stylesheets: false,
23106 // private properties
23107 validationEvent : false,
23109 initialized : false,
23111 sourceEditMode : false,
23112 onFocus : Roo.emptyFn,
23114 hideMode:'offsets',
23118 // blacklist + whitelisted elements..
23125 * Protected method that will not generally be called directly. It
23126 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23127 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23129 getDocMarkup : function(){
23133 // inherit styels from page...??
23134 if (this.stylesheets === false) {
23136 Roo.get(document.head).select('style').each(function(node) {
23137 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23140 Roo.get(document.head).select('link').each(function(node) {
23141 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23144 } else if (!this.stylesheets.length) {
23146 st = '<style type="text/css">' +
23147 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23150 st = '<style type="text/css">' +
23155 st += '<style type="text/css">' +
23156 'IMG { cursor: pointer } ' +
23159 var cls = 'roo-htmleditor-body';
23161 if(this.bodyCls.length){
23162 cls += ' ' + this.bodyCls;
23165 return '<html><head>' + st +
23166 //<style type="text/css">' +
23167 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23169 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
23173 onRender : function(ct, position)
23176 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
23177 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
23180 this.el.dom.style.border = '0 none';
23181 this.el.dom.setAttribute('tabIndex', -1);
23182 this.el.addClass('x-hidden hide');
23186 if(Roo.isIE){ // fix IE 1px bogus margin
23187 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
23191 this.frameId = Roo.id();
23195 var iframe = this.owner.wrap.createChild({
23197 cls: 'form-control', // bootstrap..
23199 name: this.frameId,
23200 frameBorder : 'no',
23201 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
23206 this.iframe = iframe.dom;
23208 this.assignDocWin();
23210 this.doc.designMode = 'on';
23213 this.doc.write(this.getDocMarkup());
23217 var task = { // must defer to wait for browser to be ready
23219 //console.log("run task?" + this.doc.readyState);
23220 this.assignDocWin();
23221 if(this.doc.body || this.doc.readyState == 'complete'){
23223 this.doc.designMode="on";
23227 Roo.TaskMgr.stop(task);
23228 this.initEditor.defer(10, this);
23235 Roo.TaskMgr.start(task);
23240 onResize : function(w, h)
23242 Roo.log('resize: ' +w + ',' + h );
23243 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
23247 if(typeof w == 'number'){
23249 this.iframe.style.width = w + 'px';
23251 if(typeof h == 'number'){
23253 this.iframe.style.height = h + 'px';
23255 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
23262 * Toggles the editor between standard and source edit mode.
23263 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23265 toggleSourceEdit : function(sourceEditMode){
23267 this.sourceEditMode = sourceEditMode === true;
23269 if(this.sourceEditMode){
23271 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
23274 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
23275 //this.iframe.className = '';
23278 //this.setSize(this.owner.wrap.getSize());
23279 //this.fireEvent('editmodechange', this, this.sourceEditMode);
23286 * Protected method that will not generally be called directly. If you need/want
23287 * custom HTML cleanup, this is the method you should override.
23288 * @param {String} html The HTML to be cleaned
23289 * return {String} The cleaned HTML
23291 cleanHtml : function(html){
23292 html = String(html);
23293 if(html.length > 5){
23294 if(Roo.isSafari){ // strip safari nonsense
23295 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
23298 if(html == ' '){
23305 * HTML Editor -> Textarea
23306 * Protected method that will not generally be called directly. Syncs the contents
23307 * of the editor iframe with the textarea.
23309 syncValue : function(){
23310 if(this.initialized){
23311 var bd = (this.doc.body || this.doc.documentElement);
23312 //this.cleanUpPaste(); -- this is done else where and causes havoc..
23313 var html = bd.innerHTML;
23315 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
23316 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
23318 html = '<div style="'+m[0]+'">' + html + '</div>';
23321 html = this.cleanHtml(html);
23322 // fix up the special chars.. normaly like back quotes in word...
23323 // however we do not want to do this with chinese..
23324 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
23326 var cc = match.charCodeAt();
23328 // Get the character value, handling surrogate pairs
23329 if (match.length == 2) {
23330 // It's a surrogate pair, calculate the Unicode code point
23331 var high = match.charCodeAt(0) - 0xD800;
23332 var low = match.charCodeAt(1) - 0xDC00;
23333 cc = (high * 0x400) + low + 0x10000;
23335 (cc >= 0x4E00 && cc < 0xA000 ) ||
23336 (cc >= 0x3400 && cc < 0x4E00 ) ||
23337 (cc >= 0xf900 && cc < 0xfb00 )
23342 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
23343 return "&#" + cc + ";";
23350 if(this.owner.fireEvent('beforesync', this, html) !== false){
23351 this.el.dom.value = html;
23352 this.owner.fireEvent('sync', this, html);
23358 * Protected method that will not generally be called directly. Pushes the value of the textarea
23359 * into the iframe editor.
23361 pushValue : function(){
23362 if(this.initialized){
23363 var v = this.el.dom.value.trim();
23365 // if(v.length < 1){
23369 if(this.owner.fireEvent('beforepush', this, v) !== false){
23370 var d = (this.doc.body || this.doc.documentElement);
23372 this.cleanUpPaste();
23373 this.el.dom.value = d.innerHTML;
23374 this.owner.fireEvent('push', this, v);
23380 deferFocus : function(){
23381 this.focus.defer(10, this);
23385 focus : function(){
23386 if(this.win && !this.sourceEditMode){
23393 assignDocWin: function()
23395 var iframe = this.iframe;
23398 this.doc = iframe.contentWindow.document;
23399 this.win = iframe.contentWindow;
23401 // if (!Roo.get(this.frameId)) {
23404 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
23405 // this.win = Roo.get(this.frameId).dom.contentWindow;
23407 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
23411 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
23412 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
23417 initEditor : function(){
23418 //console.log("INIT EDITOR");
23419 this.assignDocWin();
23423 this.doc.designMode="on";
23425 this.doc.write(this.getDocMarkup());
23428 var dbody = (this.doc.body || this.doc.documentElement);
23429 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
23430 // this copies styles from the containing element into thsi one..
23431 // not sure why we need all of this..
23432 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
23434 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
23435 //ss['background-attachment'] = 'fixed'; // w3c
23436 dbody.bgProperties = 'fixed'; // ie
23437 //Roo.DomHelper.applyStyles(dbody, ss);
23438 Roo.EventManager.on(this.doc, {
23439 //'mousedown': this.onEditorEvent,
23440 'mouseup': this.onEditorEvent,
23441 'dblclick': this.onEditorEvent,
23442 'click': this.onEditorEvent,
23443 'keyup': this.onEditorEvent,
23448 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
23450 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
23451 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
23453 this.initialized = true;
23455 this.owner.fireEvent('initialize', this);
23460 onDestroy : function(){
23466 //for (var i =0; i < this.toolbars.length;i++) {
23467 // // fixme - ask toolbars for heights?
23468 // this.toolbars[i].onDestroy();
23471 //this.wrap.dom.innerHTML = '';
23472 //this.wrap.remove();
23477 onFirstFocus : function(){
23479 this.assignDocWin();
23482 this.activated = true;
23485 if(Roo.isGecko){ // prevent silly gecko errors
23487 var s = this.win.getSelection();
23488 if(!s.focusNode || s.focusNode.nodeType != 3){
23489 var r = s.getRangeAt(0);
23490 r.selectNodeContents((this.doc.body || this.doc.documentElement));
23495 this.execCmd('useCSS', true);
23496 this.execCmd('styleWithCSS', false);
23499 this.owner.fireEvent('activate', this);
23503 adjustFont: function(btn){
23504 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
23505 //if(Roo.isSafari){ // safari
23508 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
23509 if(Roo.isSafari){ // safari
23510 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
23511 v = (v < 10) ? 10 : v;
23512 v = (v > 48) ? 48 : v;
23513 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
23518 v = Math.max(1, v+adjust);
23520 this.execCmd('FontSize', v );
23523 onEditorEvent : function(e)
23525 this.owner.fireEvent('editorevent', this, e);
23526 // this.updateToolbar();
23527 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
23530 insertTag : function(tg)
23532 // could be a bit smarter... -> wrap the current selected tRoo..
23533 if (tg.toLowerCase() == 'span' ||
23534 tg.toLowerCase() == 'code' ||
23535 tg.toLowerCase() == 'sup' ||
23536 tg.toLowerCase() == 'sub'
23539 range = this.createRange(this.getSelection());
23540 var wrappingNode = this.doc.createElement(tg.toLowerCase());
23541 wrappingNode.appendChild(range.extractContents());
23542 range.insertNode(wrappingNode);
23549 this.execCmd("formatblock", tg);
23553 insertText : function(txt)
23557 var range = this.createRange();
23558 range.deleteContents();
23559 //alert(Sender.getAttribute('label'));
23561 range.insertNode(this.doc.createTextNode(txt));
23567 * Executes a Midas editor command on the editor document and performs necessary focus and
23568 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
23569 * @param {String} cmd The Midas command
23570 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
23572 relayCmd : function(cmd, value){
23574 this.execCmd(cmd, value);
23575 this.owner.fireEvent('editorevent', this);
23576 //this.updateToolbar();
23577 this.owner.deferFocus();
23581 * Executes a Midas editor command directly on the editor document.
23582 * For visual commands, you should use {@link #relayCmd} instead.
23583 * <b>This should only be called after the editor is initialized.</b>
23584 * @param {String} cmd The Midas command
23585 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
23587 execCmd : function(cmd, value){
23588 this.doc.execCommand(cmd, false, value === undefined ? null : value);
23595 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
23597 * @param {String} text | dom node..
23599 insertAtCursor : function(text)
23602 if(!this.activated){
23608 var r = this.doc.selection.createRange();
23619 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
23623 // from jquery ui (MIT licenced)
23625 var win = this.win;
23627 if (win.getSelection && win.getSelection().getRangeAt) {
23628 range = win.getSelection().getRangeAt(0);
23629 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
23630 range.insertNode(node);
23631 } else if (win.document.selection && win.document.selection.createRange) {
23632 // no firefox support
23633 var txt = typeof(text) == 'string' ? text : text.outerHTML;
23634 win.document.selection.createRange().pasteHTML(txt);
23636 // no firefox support
23637 var txt = typeof(text) == 'string' ? text : text.outerHTML;
23638 this.execCmd('InsertHTML', txt);
23647 mozKeyPress : function(e){
23649 var c = e.getCharCode(), cmd;
23652 c = String.fromCharCode(c).toLowerCase();
23666 this.cleanUpPaste.defer(100, this);
23674 e.preventDefault();
23682 fixKeys : function(){ // load time branching for fastest keydown performance
23684 return function(e){
23685 var k = e.getKey(), r;
23688 r = this.doc.selection.createRange();
23691 r.pasteHTML('    ');
23698 r = this.doc.selection.createRange();
23700 var target = r.parentElement();
23701 if(!target || target.tagName.toLowerCase() != 'li'){
23703 r.pasteHTML('<br />');
23709 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23710 this.cleanUpPaste.defer(100, this);
23716 }else if(Roo.isOpera){
23717 return function(e){
23718 var k = e.getKey();
23722 this.execCmd('InsertHTML','    ');
23725 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23726 this.cleanUpPaste.defer(100, this);
23731 }else if(Roo.isSafari){
23732 return function(e){
23733 var k = e.getKey();
23737 this.execCmd('InsertText','\t');
23741 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
23742 this.cleanUpPaste.defer(100, this);
23750 getAllAncestors: function()
23752 var p = this.getSelectedNode();
23755 a.push(p); // push blank onto stack..
23756 p = this.getParentElement();
23760 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
23764 a.push(this.doc.body);
23768 lastSelNode : false,
23771 getSelection : function()
23773 this.assignDocWin();
23774 return Roo.isIE ? this.doc.selection : this.win.getSelection();
23777 getSelectedNode: function()
23779 // this may only work on Gecko!!!
23781 // should we cache this!!!!
23786 var range = this.createRange(this.getSelection()).cloneRange();
23789 var parent = range.parentElement();
23791 var testRange = range.duplicate();
23792 testRange.moveToElementText(parent);
23793 if (testRange.inRange(range)) {
23796 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
23799 parent = parent.parentElement;
23804 // is ancestor a text element.
23805 var ac = range.commonAncestorContainer;
23806 if (ac.nodeType == 3) {
23807 ac = ac.parentNode;
23810 var ar = ac.childNodes;
23813 var other_nodes = [];
23814 var has_other_nodes = false;
23815 for (var i=0;i<ar.length;i++) {
23816 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
23819 // fullly contained node.
23821 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
23826 // probably selected..
23827 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
23828 other_nodes.push(ar[i]);
23832 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
23837 has_other_nodes = true;
23839 if (!nodes.length && other_nodes.length) {
23840 nodes= other_nodes;
23842 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
23848 createRange: function(sel)
23850 // this has strange effects when using with
23851 // top toolbar - not sure if it's a great idea.
23852 //this.editor.contentWindow.focus();
23853 if (typeof sel != "undefined") {
23855 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
23857 return this.doc.createRange();
23860 return this.doc.createRange();
23863 getParentElement: function()
23866 this.assignDocWin();
23867 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
23869 var range = this.createRange(sel);
23872 var p = range.commonAncestorContainer;
23873 while (p.nodeType == 3) { // text node
23884 * Range intersection.. the hard stuff...
23888 * [ -- selected range --- ]
23892 * if end is before start or hits it. fail.
23893 * if start is after end or hits it fail.
23895 * if either hits (but other is outside. - then it's not
23901 // @see http://www.thismuchiknow.co.uk/?p=64.
23902 rangeIntersectsNode : function(range, node)
23904 var nodeRange = node.ownerDocument.createRange();
23906 nodeRange.selectNode(node);
23908 nodeRange.selectNodeContents(node);
23911 var rangeStartRange = range.cloneRange();
23912 rangeStartRange.collapse(true);
23914 var rangeEndRange = range.cloneRange();
23915 rangeEndRange.collapse(false);
23917 var nodeStartRange = nodeRange.cloneRange();
23918 nodeStartRange.collapse(true);
23920 var nodeEndRange = nodeRange.cloneRange();
23921 nodeEndRange.collapse(false);
23923 return rangeStartRange.compareBoundaryPoints(
23924 Range.START_TO_START, nodeEndRange) == -1 &&
23925 rangeEndRange.compareBoundaryPoints(
23926 Range.START_TO_START, nodeStartRange) == 1;
23930 rangeCompareNode : function(range, node)
23932 var nodeRange = node.ownerDocument.createRange();
23934 nodeRange.selectNode(node);
23936 nodeRange.selectNodeContents(node);
23940 range.collapse(true);
23942 nodeRange.collapse(true);
23944 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
23945 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
23947 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
23949 var nodeIsBefore = ss == 1;
23950 var nodeIsAfter = ee == -1;
23952 if (nodeIsBefore && nodeIsAfter) {
23955 if (!nodeIsBefore && nodeIsAfter) {
23956 return 1; //right trailed.
23959 if (nodeIsBefore && !nodeIsAfter) {
23960 return 2; // left trailed.
23966 // private? - in a new class?
23967 cleanUpPaste : function()
23969 // cleans up the whole document..
23970 Roo.log('cleanuppaste');
23972 this.cleanUpChildren(this.doc.body);
23973 var clean = this.cleanWordChars(this.doc.body.innerHTML);
23974 if (clean != this.doc.body.innerHTML) {
23975 this.doc.body.innerHTML = clean;
23980 cleanWordChars : function(input) {// change the chars to hex code
23981 var he = Roo.HtmlEditorCore;
23983 var output = input;
23984 Roo.each(he.swapCodes, function(sw) {
23985 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
23987 output = output.replace(swapper, sw[1]);
23994 cleanUpChildren : function (n)
23996 if (!n.childNodes.length) {
23999 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24000 this.cleanUpChild(n.childNodes[i]);
24007 cleanUpChild : function (node)
24010 //console.log(node);
24011 if (node.nodeName == "#text") {
24012 // clean up silly Windows -- stuff?
24015 if (node.nodeName == "#comment") {
24016 node.parentNode.removeChild(node);
24017 // clean up silly Windows -- stuff?
24020 var lcname = node.tagName.toLowerCase();
24021 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
24022 // whitelist of tags..
24024 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
24026 node.parentNode.removeChild(node);
24031 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
24033 // spans with no attributes - just remove them..
24034 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
24035 remove_keep_children = true;
24038 // remove <a name=....> as rendering on yahoo mailer is borked with this.
24039 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
24041 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
24042 // remove_keep_children = true;
24045 if (remove_keep_children) {
24046 this.cleanUpChildren(node);
24047 // inserts everything just before this node...
24048 while (node.childNodes.length) {
24049 var cn = node.childNodes[0];
24050 node.removeChild(cn);
24051 node.parentNode.insertBefore(cn, node);
24053 node.parentNode.removeChild(node);
24057 if (!node.attributes || !node.attributes.length) {
24062 this.cleanUpChildren(node);
24066 function cleanAttr(n,v)
24069 if (v.match(/^\./) || v.match(/^\//)) {
24072 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
24075 if (v.match(/^#/)) {
24078 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
24079 node.removeAttribute(n);
24083 var cwhite = this.cwhite;
24084 var cblack = this.cblack;
24086 function cleanStyle(n,v)
24088 if (v.match(/expression/)) { //XSS?? should we even bother..
24089 node.removeAttribute(n);
24093 var parts = v.split(/;/);
24096 Roo.each(parts, function(p) {
24097 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
24101 var l = p.split(':').shift().replace(/\s+/g,'');
24102 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
24104 if ( cwhite.length && cblack.indexOf(l) > -1) {
24105 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24106 //node.removeAttribute(n);
24110 // only allow 'c whitelisted system attributes'
24111 if ( cwhite.length && cwhite.indexOf(l) < 0) {
24112 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24113 //node.removeAttribute(n);
24123 if (clean.length) {
24124 node.setAttribute(n, clean.join(';'));
24126 node.removeAttribute(n);
24132 for (var i = node.attributes.length-1; i > -1 ; i--) {
24133 var a = node.attributes[i];
24136 if (a.name.toLowerCase().substr(0,2)=='on') {
24137 node.removeAttribute(a.name);
24140 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
24141 node.removeAttribute(a.name);
24144 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
24145 cleanAttr(a.name,a.value); // fixme..
24148 if (a.name == 'style') {
24149 cleanStyle(a.name,a.value);
24152 /// clean up MS crap..
24153 // tecnically this should be a list of valid class'es..
24156 if (a.name == 'class') {
24157 if (a.value.match(/^Mso/)) {
24158 node.removeAttribute('class');
24161 if (a.value.match(/^body$/)) {
24162 node.removeAttribute('class');
24173 this.cleanUpChildren(node);
24179 * Clean up MS wordisms...
24181 cleanWord : function(node)
24184 this.cleanWord(this.doc.body);
24189 node.nodeName == 'SPAN' &&
24190 !node.hasAttributes() &&
24191 node.childNodes.length == 1 &&
24192 node.firstChild.nodeName == "#text"
24194 var textNode = node.firstChild;
24195 node.removeChild(textNode);
24196 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24197 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
24199 node.parentNode.insertBefore(textNode, node);
24200 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24201 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
24203 node.parentNode.removeChild(node);
24206 if (node.nodeName == "#text") {
24207 // clean up silly Windows -- stuff?
24210 if (node.nodeName == "#comment") {
24211 node.parentNode.removeChild(node);
24212 // clean up silly Windows -- stuff?
24216 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
24217 node.parentNode.removeChild(node);
24220 //Roo.log(node.tagName);
24221 // remove - but keep children..
24222 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
24223 //Roo.log('-- removed');
24224 while (node.childNodes.length) {
24225 var cn = node.childNodes[0];
24226 node.removeChild(cn);
24227 node.parentNode.insertBefore(cn, node);
24228 // move node to parent - and clean it..
24229 this.cleanWord(cn);
24231 node.parentNode.removeChild(node);
24232 /// no need to iterate chidlren = it's got none..
24233 //this.iterateChildren(node, this.cleanWord);
24237 if (node.className.length) {
24239 var cn = node.className.split(/\W+/);
24241 Roo.each(cn, function(cls) {
24242 if (cls.match(/Mso[a-zA-Z]+/)) {
24247 node.className = cna.length ? cna.join(' ') : '';
24249 node.removeAttribute("class");
24253 if (node.hasAttribute("lang")) {
24254 node.removeAttribute("lang");
24257 if (node.hasAttribute("style")) {
24259 var styles = node.getAttribute("style").split(";");
24261 Roo.each(styles, function(s) {
24262 if (!s.match(/:/)) {
24265 var kv = s.split(":");
24266 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
24269 // what ever is left... we allow.
24272 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
24273 if (!nstyle.length) {
24274 node.removeAttribute('style');
24277 this.iterateChildren(node, this.cleanWord);
24283 * iterateChildren of a Node, calling fn each time, using this as the scole..
24284 * @param {DomNode} node node to iterate children of.
24285 * @param {Function} fn method of this class to call on each item.
24287 iterateChildren : function(node, fn)
24289 if (!node.childNodes.length) {
24292 for (var i = node.childNodes.length-1; i > -1 ; i--) {
24293 fn.call(this, node.childNodes[i])
24299 * cleanTableWidths.
24301 * Quite often pasting from word etc.. results in tables with column and widths.
24302 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
24305 cleanTableWidths : function(node)
24310 this.cleanTableWidths(this.doc.body);
24315 if (node.nodeName == "#text" || node.nodeName == "#comment") {
24318 Roo.log(node.tagName);
24319 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
24320 this.iterateChildren(node, this.cleanTableWidths);
24323 if (node.hasAttribute('width')) {
24324 node.removeAttribute('width');
24328 if (node.hasAttribute("style")) {
24331 var styles = node.getAttribute("style").split(";");
24333 Roo.each(styles, function(s) {
24334 if (!s.match(/:/)) {
24337 var kv = s.split(":");
24338 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
24341 // what ever is left... we allow.
24344 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
24345 if (!nstyle.length) {
24346 node.removeAttribute('style');
24350 this.iterateChildren(node, this.cleanTableWidths);
24358 domToHTML : function(currentElement, depth, nopadtext) {
24360 depth = depth || 0;
24361 nopadtext = nopadtext || false;
24363 if (!currentElement) {
24364 return this.domToHTML(this.doc.body);
24367 //Roo.log(currentElement);
24369 var allText = false;
24370 var nodeName = currentElement.nodeName;
24371 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
24373 if (nodeName == '#text') {
24375 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
24380 if (nodeName != 'BODY') {
24383 // Prints the node tagName, such as <A>, <IMG>, etc
24386 for(i = 0; i < currentElement.attributes.length;i++) {
24388 var aname = currentElement.attributes.item(i).name;
24389 if (!currentElement.attributes.item(i).value.length) {
24392 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
24395 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
24404 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
24407 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
24412 // Traverse the tree
24414 var currentElementChild = currentElement.childNodes.item(i);
24415 var allText = true;
24416 var innerHTML = '';
24418 while (currentElementChild) {
24419 // Formatting code (indent the tree so it looks nice on the screen)
24420 var nopad = nopadtext;
24421 if (lastnode == 'SPAN') {
24425 if (currentElementChild.nodeName == '#text') {
24426 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
24427 toadd = nopadtext ? toadd : toadd.trim();
24428 if (!nopad && toadd.length > 80) {
24429 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
24431 innerHTML += toadd;
24434 currentElementChild = currentElement.childNodes.item(i);
24440 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
24442 // Recursively traverse the tree structure of the child node
24443 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
24444 lastnode = currentElementChild.nodeName;
24446 currentElementChild=currentElement.childNodes.item(i);
24452 // The remaining code is mostly for formatting the tree
24453 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
24458 ret+= "</"+tagName+">";
24464 applyBlacklists : function()
24466 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
24467 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
24471 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
24472 if (b.indexOf(tag) > -1) {
24475 this.white.push(tag);
24479 Roo.each(w, function(tag) {
24480 if (b.indexOf(tag) > -1) {
24483 if (this.white.indexOf(tag) > -1) {
24486 this.white.push(tag);
24491 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
24492 if (w.indexOf(tag) > -1) {
24495 this.black.push(tag);
24499 Roo.each(b, function(tag) {
24500 if (w.indexOf(tag) > -1) {
24503 if (this.black.indexOf(tag) > -1) {
24506 this.black.push(tag);
24511 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
24512 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
24516 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
24517 if (b.indexOf(tag) > -1) {
24520 this.cwhite.push(tag);
24524 Roo.each(w, function(tag) {
24525 if (b.indexOf(tag) > -1) {
24528 if (this.cwhite.indexOf(tag) > -1) {
24531 this.cwhite.push(tag);
24536 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
24537 if (w.indexOf(tag) > -1) {
24540 this.cblack.push(tag);
24544 Roo.each(b, function(tag) {
24545 if (w.indexOf(tag) > -1) {
24548 if (this.cblack.indexOf(tag) > -1) {
24551 this.cblack.push(tag);
24556 setStylesheets : function(stylesheets)
24558 if(typeof(stylesheets) == 'string'){
24559 Roo.get(this.iframe.contentDocument.head).createChild({
24561 rel : 'stylesheet',
24570 Roo.each(stylesheets, function(s) {
24575 Roo.get(_this.iframe.contentDocument.head).createChild({
24577 rel : 'stylesheet',
24586 removeStylesheets : function()
24590 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
24595 setStyle : function(style)
24597 Roo.get(this.iframe.contentDocument.head).createChild({
24606 // hide stuff that is not compatible
24620 * @event specialkey
24624 * @cfg {String} fieldClass @hide
24627 * @cfg {String} focusClass @hide
24630 * @cfg {String} autoCreate @hide
24633 * @cfg {String} inputType @hide
24636 * @cfg {String} invalidClass @hide
24639 * @cfg {String} invalidText @hide
24642 * @cfg {String} msgFx @hide
24645 * @cfg {String} validateOnBlur @hide
24649 Roo.HtmlEditorCore.white = [
24650 'area', 'br', 'img', 'input', 'hr', 'wbr',
24652 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24653 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24654 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24655 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24656 'table', 'ul', 'xmp',
24658 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24661 'dir', 'menu', 'ol', 'ul', 'dl',
24667 Roo.HtmlEditorCore.black = [
24668 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24670 'base', 'basefont', 'bgsound', 'blink', 'body',
24671 'frame', 'frameset', 'head', 'html', 'ilayer',
24672 'iframe', 'layer', 'link', 'meta', 'object',
24673 'script', 'style' ,'title', 'xml' // clean later..
24675 Roo.HtmlEditorCore.clean = [
24676 'script', 'style', 'title', 'xml'
24678 Roo.HtmlEditorCore.remove = [
24683 Roo.HtmlEditorCore.ablack = [
24687 Roo.HtmlEditorCore.aclean = [
24688 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24692 Roo.HtmlEditorCore.pwhite= [
24693 'http', 'https', 'mailto'
24696 // white listed style attributes.
24697 Roo.HtmlEditorCore.cwhite= [
24698 // 'text-align', /// default is to allow most things..
24704 // black listed style attributes.
24705 Roo.HtmlEditorCore.cblack= [
24706 // 'font-size' -- this can be set by the project
24710 Roo.HtmlEditorCore.swapCodes =[
24729 * @class Roo.bootstrap.HtmlEditor
24730 * @extends Roo.bootstrap.TextArea
24731 * Bootstrap HtmlEditor class
24734 * Create a new HtmlEditor
24735 * @param {Object} config The config object
24738 Roo.bootstrap.HtmlEditor = function(config){
24739 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
24740 if (!this.toolbars) {
24741 this.toolbars = [];
24744 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
24747 * @event initialize
24748 * Fires when the editor is fully initialized (including the iframe)
24749 * @param {HtmlEditor} this
24754 * Fires when the editor is first receives the focus. Any insertion must wait
24755 * until after this event.
24756 * @param {HtmlEditor} this
24760 * @event beforesync
24761 * Fires before the textarea is updated with content from the editor iframe. Return false
24762 * to cancel the sync.
24763 * @param {HtmlEditor} this
24764 * @param {String} html
24768 * @event beforepush
24769 * Fires before the iframe editor is updated with content from the textarea. Return false
24770 * to cancel the push.
24771 * @param {HtmlEditor} this
24772 * @param {String} html
24777 * Fires when the textarea is updated with content from the editor iframe.
24778 * @param {HtmlEditor} this
24779 * @param {String} html
24784 * Fires when the iframe editor is updated with content from the textarea.
24785 * @param {HtmlEditor} this
24786 * @param {String} html
24790 * @event editmodechange
24791 * Fires when the editor switches edit modes
24792 * @param {HtmlEditor} this
24793 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
24795 editmodechange: true,
24797 * @event editorevent
24798 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
24799 * @param {HtmlEditor} this
24803 * @event firstfocus
24804 * Fires when on first focus - needed by toolbars..
24805 * @param {HtmlEditor} this
24810 * Auto save the htmlEditor value as a file into Events
24811 * @param {HtmlEditor} this
24815 * @event savedpreview
24816 * preview the saved version of htmlEditor
24817 * @param {HtmlEditor} this
24824 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
24828 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
24833 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
24838 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
24843 * @cfg {Number} height (in pixels)
24847 * @cfg {Number} width (in pixels)
24852 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
24855 stylesheets: false,
24860 // private properties
24861 validationEvent : false,
24863 initialized : false,
24866 onFocus : Roo.emptyFn,
24868 hideMode:'offsets',
24870 tbContainer : false,
24874 toolbarContainer :function() {
24875 return this.wrap.select('.x-html-editor-tb',true).first();
24879 * Protected method that will not generally be called directly. It
24880 * is called when the editor creates its toolbar. Override this method if you need to
24881 * add custom toolbar buttons.
24882 * @param {HtmlEditor} editor
24884 createToolbar : function(){
24885 Roo.log('renewing');
24886 Roo.log("create toolbars");
24888 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
24889 this.toolbars[0].render(this.toolbarContainer());
24893 // if (!editor.toolbars || !editor.toolbars.length) {
24894 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
24897 // for (var i =0 ; i < editor.toolbars.length;i++) {
24898 // editor.toolbars[i] = Roo.factory(
24899 // typeof(editor.toolbars[i]) == 'string' ?
24900 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
24901 // Roo.bootstrap.HtmlEditor);
24902 // editor.toolbars[i].init(editor);
24908 onRender : function(ct, position)
24910 // Roo.log("Call onRender: " + this.xtype);
24912 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
24914 this.wrap = this.inputEl().wrap({
24915 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24918 this.editorcore.onRender(ct, position);
24920 if (this.resizable) {
24921 this.resizeEl = new Roo.Resizable(this.wrap, {
24925 minHeight : this.height,
24926 height: this.height,
24927 handles : this.resizable,
24930 resize : function(r, w, h) {
24931 _t.onResize(w,h); // -something
24937 this.createToolbar(this);
24940 if(!this.width && this.resizable){
24941 this.setSize(this.wrap.getSize());
24943 if (this.resizeEl) {
24944 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
24945 // should trigger onReize..
24951 onResize : function(w, h)
24953 Roo.log('resize: ' +w + ',' + h );
24954 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
24958 if(this.inputEl() ){
24959 if(typeof w == 'number'){
24960 var aw = w - this.wrap.getFrameWidth('lr');
24961 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
24964 if(typeof h == 'number'){
24965 var tbh = -11; // fixme it needs to tool bar size!
24966 for (var i =0; i < this.toolbars.length;i++) {
24967 // fixme - ask toolbars for heights?
24968 tbh += this.toolbars[i].el.getHeight();
24969 //if (this.toolbars[i].footer) {
24970 // tbh += this.toolbars[i].footer.el.getHeight();
24978 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24979 ah -= 5; // knock a few pixes off for look..
24980 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
24984 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
24985 this.editorcore.onResize(ew,eh);
24990 * Toggles the editor between standard and source edit mode.
24991 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24993 toggleSourceEdit : function(sourceEditMode)
24995 this.editorcore.toggleSourceEdit(sourceEditMode);
24997 if(this.editorcore.sourceEditMode){
24998 Roo.log('editor - showing textarea');
25001 // Roo.log(this.syncValue());
25003 this.inputEl().removeClass(['hide', 'x-hidden']);
25004 this.inputEl().dom.removeAttribute('tabIndex');
25005 this.inputEl().focus();
25007 Roo.log('editor - hiding textarea');
25009 // Roo.log(this.pushValue());
25012 this.inputEl().addClass(['hide', 'x-hidden']);
25013 this.inputEl().dom.setAttribute('tabIndex', -1);
25014 //this.deferFocus();
25017 if(this.resizable){
25018 this.setSize(this.wrap.getSize());
25021 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
25024 // private (for BoxComponent)
25025 adjustSize : Roo.BoxComponent.prototype.adjustSize,
25027 // private (for BoxComponent)
25028 getResizeEl : function(){
25032 // private (for BoxComponent)
25033 getPositionEl : function(){
25038 initEvents : function(){
25039 this.originalValue = this.getValue();
25043 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25046 // markInvalid : Roo.emptyFn,
25048 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25051 // clearInvalid : Roo.emptyFn,
25053 setValue : function(v){
25054 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
25055 this.editorcore.pushValue();
25060 deferFocus : function(){
25061 this.focus.defer(10, this);
25065 focus : function(){
25066 this.editorcore.focus();
25072 onDestroy : function(){
25078 for (var i =0; i < this.toolbars.length;i++) {
25079 // fixme - ask toolbars for heights?
25080 this.toolbars[i].onDestroy();
25083 this.wrap.dom.innerHTML = '';
25084 this.wrap.remove();
25089 onFirstFocus : function(){
25090 //Roo.log("onFirstFocus");
25091 this.editorcore.onFirstFocus();
25092 for (var i =0; i < this.toolbars.length;i++) {
25093 this.toolbars[i].onFirstFocus();
25099 syncValue : function()
25101 this.editorcore.syncValue();
25104 pushValue : function()
25106 this.editorcore.pushValue();
25110 // hide stuff that is not compatible
25124 * @event specialkey
25128 * @cfg {String} fieldClass @hide
25131 * @cfg {String} focusClass @hide
25134 * @cfg {String} autoCreate @hide
25137 * @cfg {String} inputType @hide
25141 * @cfg {String} invalidText @hide
25144 * @cfg {String} msgFx @hide
25147 * @cfg {String} validateOnBlur @hide
25156 Roo.namespace('Roo.bootstrap.htmleditor');
25158 * @class Roo.bootstrap.HtmlEditorToolbar1
25164 new Roo.bootstrap.HtmlEditor({
25167 new Roo.bootstrap.HtmlEditorToolbar1({
25168 disable : { fonts: 1 , format: 1, ..., ... , ...],
25174 * @cfg {Object} disable List of elements to disable..
25175 * @cfg {Array} btns List of additional buttons.
25179 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
25182 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
25185 Roo.apply(this, config);
25187 // default disabled, based on 'good practice'..
25188 this.disable = this.disable || {};
25189 Roo.applyIf(this.disable, {
25192 specialElements : true
25194 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
25196 this.editor = config.editor;
25197 this.editorcore = config.editor.editorcore;
25199 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
25201 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25202 // dont call parent... till later.
25204 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
25209 editorcore : false,
25214 "h1","h2","h3","h4","h5","h6",
25216 "abbr", "acronym", "address", "cite", "samp", "var",
25220 onRender : function(ct, position)
25222 // Roo.log("Call onRender: " + this.xtype);
25224 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
25226 this.el.dom.style.marginBottom = '0';
25228 var editorcore = this.editorcore;
25229 var editor= this.editor;
25232 var btn = function(id,cmd , toggle, handler, html){
25234 var event = toggle ? 'toggle' : 'click';
25239 xns: Roo.bootstrap,
25243 enableToggle:toggle !== false,
25245 pressed : toggle ? false : null,
25248 a.listeners[toggle ? 'toggle' : 'click'] = function() {
25249 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
25255 // var cb_box = function...
25260 xns: Roo.bootstrap,
25265 xns: Roo.bootstrap,
25269 Roo.each(this.formats, function(f) {
25270 style.menu.items.push({
25272 xns: Roo.bootstrap,
25273 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
25278 editorcore.insertTag(this.tagname);
25285 children.push(style);
25287 btn('bold',false,true);
25288 btn('italic',false,true);
25289 btn('align-left', 'justifyleft',true);
25290 btn('align-center', 'justifycenter',true);
25291 btn('align-right' , 'justifyright',true);
25292 btn('link', false, false, function(btn) {
25293 //Roo.log("create link?");
25294 var url = prompt(this.createLinkText, this.defaultLinkValue);
25295 if(url && url != 'http:/'+'/'){
25296 this.editorcore.relayCmd('createlink', url);
25299 btn('list','insertunorderedlist',true);
25300 btn('pencil', false,true, function(btn){
25302 this.toggleSourceEdit(btn.pressed);
25305 if (this.editor.btns.length > 0) {
25306 for (var i = 0; i<this.editor.btns.length; i++) {
25307 children.push(this.editor.btns[i]);
25315 xns: Roo.bootstrap,
25320 xns: Roo.bootstrap,
25325 cog.menu.items.push({
25327 xns: Roo.bootstrap,
25328 html : Clean styles,
25333 editorcore.insertTag(this.tagname);
25342 this.xtype = 'NavSimplebar';
25344 for(var i=0;i< children.length;i++) {
25346 this.buttons.add(this.addxtypeChild(children[i]));
25350 editor.on('editorevent', this.updateToolbar, this);
25352 onBtnClick : function(id)
25354 this.editorcore.relayCmd(id);
25355 this.editorcore.focus();
25359 * Protected method that will not generally be called directly. It triggers
25360 * a toolbar update by reading the markup state of the current selection in the editor.
25362 updateToolbar: function(){
25364 if(!this.editorcore.activated){
25365 this.editor.onFirstFocus(); // is this neeed?
25369 var btns = this.buttons;
25370 var doc = this.editorcore.doc;
25371 btns.get('bold').setActive(doc.queryCommandState('bold'));
25372 btns.get('italic').setActive(doc.queryCommandState('italic'));
25373 //btns.get('underline').setActive(doc.queryCommandState('underline'));
25375 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
25376 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
25377 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
25379 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
25380 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
25383 var ans = this.editorcore.getAllAncestors();
25384 if (this.formatCombo) {
25387 var store = this.formatCombo.store;
25388 this.formatCombo.setValue("");
25389 for (var i =0; i < ans.length;i++) {
25390 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25392 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25400 // hides menus... - so this cant be on a menu...
25401 Roo.bootstrap.MenuMgr.hideAll();
25403 Roo.bootstrap.MenuMgr.hideAll();
25404 //this.editorsyncValue();
25406 onFirstFocus: function() {
25407 this.buttons.each(function(item){
25411 toggleSourceEdit : function(sourceEditMode){
25414 if(sourceEditMode){
25415 Roo.log("disabling buttons");
25416 this.buttons.each( function(item){
25417 if(item.cmd != 'pencil'){
25423 Roo.log("enabling buttons");
25424 if(this.editorcore.initialized){
25425 this.buttons.each( function(item){
25431 Roo.log("calling toggole on editor");
25432 // tell the editor that it's been pressed..
25433 this.editor.toggleSourceEdit(sourceEditMode);
25443 * @class Roo.bootstrap.Table.AbstractSelectionModel
25444 * @extends Roo.util.Observable
25445 * Abstract base class for grid SelectionModels. It provides the interface that should be
25446 * implemented by descendant classes. This class should not be directly instantiated.
25449 Roo.bootstrap.Table.AbstractSelectionModel = function(){
25450 this.locked = false;
25451 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
25455 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
25456 /** @ignore Called by the grid automatically. Do not call directly. */
25457 init : function(grid){
25463 * Locks the selections.
25466 this.locked = true;
25470 * Unlocks the selections.
25472 unlock : function(){
25473 this.locked = false;
25477 * Returns true if the selections are locked.
25478 * @return {Boolean}
25480 isLocked : function(){
25481 return this.locked;
25485 initEvents : function ()
25491 * @extends Roo.bootstrap.Table.AbstractSelectionModel
25492 * @class Roo.bootstrap.Table.RowSelectionModel
25493 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
25494 * It supports multiple selections and keyboard selection/navigation.
25496 * @param {Object} config
25499 Roo.bootstrap.Table.RowSelectionModel = function(config){
25500 Roo.apply(this, config);
25501 this.selections = new Roo.util.MixedCollection(false, function(o){
25506 this.lastActive = false;
25510 * @event selectionchange
25511 * Fires when the selection changes
25512 * @param {SelectionModel} this
25514 "selectionchange" : true,
25516 * @event afterselectionchange
25517 * Fires after the selection changes (eg. by key press or clicking)
25518 * @param {SelectionModel} this
25520 "afterselectionchange" : true,
25522 * @event beforerowselect
25523 * Fires when a row is selected being selected, return false to cancel.
25524 * @param {SelectionModel} this
25525 * @param {Number} rowIndex The selected index
25526 * @param {Boolean} keepExisting False if other selections will be cleared
25528 "beforerowselect" : true,
25531 * Fires when a row is selected.
25532 * @param {SelectionModel} this
25533 * @param {Number} rowIndex The selected index
25534 * @param {Roo.data.Record} r The record
25536 "rowselect" : true,
25538 * @event rowdeselect
25539 * Fires when a row is deselected.
25540 * @param {SelectionModel} this
25541 * @param {Number} rowIndex The selected index
25543 "rowdeselect" : true
25545 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
25546 this.locked = false;
25549 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
25551 * @cfg {Boolean} singleSelect
25552 * True to allow selection of only one row at a time (defaults to false)
25554 singleSelect : false,
25557 initEvents : function()
25560 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
25561 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
25562 //}else{ // allow click to work like normal
25563 // this.grid.on("rowclick", this.handleDragableRowClick, this);
25565 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
25566 this.grid.on("rowclick", this.handleMouseDown, this);
25568 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
25569 "up" : function(e){
25571 this.selectPrevious(e.shiftKey);
25572 }else if(this.last !== false && this.lastActive !== false){
25573 var last = this.last;
25574 this.selectRange(this.last, this.lastActive-1);
25575 this.grid.getView().focusRow(this.lastActive);
25576 if(last !== false){
25580 this.selectFirstRow();
25582 this.fireEvent("afterselectionchange", this);
25584 "down" : function(e){
25586 this.selectNext(e.shiftKey);
25587 }else if(this.last !== false && this.lastActive !== false){
25588 var last = this.last;
25589 this.selectRange(this.last, this.lastActive+1);
25590 this.grid.getView().focusRow(this.lastActive);
25591 if(last !== false){
25595 this.selectFirstRow();
25597 this.fireEvent("afterselectionchange", this);
25601 this.grid.store.on('load', function(){
25602 this.selections.clear();
25605 var view = this.grid.view;
25606 view.on("refresh", this.onRefresh, this);
25607 view.on("rowupdated", this.onRowUpdated, this);
25608 view.on("rowremoved", this.onRemove, this);
25613 onRefresh : function()
25615 var ds = this.grid.store, i, v = this.grid.view;
25616 var s = this.selections;
25617 s.each(function(r){
25618 if((i = ds.indexOfId(r.id)) != -1){
25627 onRemove : function(v, index, r){
25628 this.selections.remove(r);
25632 onRowUpdated : function(v, index, r){
25633 if(this.isSelected(r)){
25634 v.onRowSelect(index);
25640 * @param {Array} records The records to select
25641 * @param {Boolean} keepExisting (optional) True to keep existing selections
25643 selectRecords : function(records, keepExisting)
25646 this.clearSelections();
25648 var ds = this.grid.store;
25649 for(var i = 0, len = records.length; i < len; i++){
25650 this.selectRow(ds.indexOf(records[i]), true);
25655 * Gets the number of selected rows.
25658 getCount : function(){
25659 return this.selections.length;
25663 * Selects the first row in the grid.
25665 selectFirstRow : function(){
25670 * Select the last row.
25671 * @param {Boolean} keepExisting (optional) True to keep existing selections
25673 selectLastRow : function(keepExisting){
25674 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
25675 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
25679 * Selects the row immediately following the last selected row.
25680 * @param {Boolean} keepExisting (optional) True to keep existing selections
25682 selectNext : function(keepExisting)
25684 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
25685 this.selectRow(this.last+1, keepExisting);
25686 this.grid.getView().focusRow(this.last);
25691 * Selects the row that precedes the last selected row.
25692 * @param {Boolean} keepExisting (optional) True to keep existing selections
25694 selectPrevious : function(keepExisting){
25696 this.selectRow(this.last-1, keepExisting);
25697 this.grid.getView().focusRow(this.last);
25702 * Returns the selected records
25703 * @return {Array} Array of selected records
25705 getSelections : function(){
25706 return [].concat(this.selections.items);
25710 * Returns the first selected record.
25713 getSelected : function(){
25714 return this.selections.itemAt(0);
25719 * Clears all selections.
25721 clearSelections : function(fast)
25727 var ds = this.grid.store;
25728 var s = this.selections;
25729 s.each(function(r){
25730 this.deselectRow(ds.indexOfId(r.id));
25734 this.selections.clear();
25741 * Selects all rows.
25743 selectAll : function(){
25747 this.selections.clear();
25748 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
25749 this.selectRow(i, true);
25754 * Returns True if there is a selection.
25755 * @return {Boolean}
25757 hasSelection : function(){
25758 return this.selections.length > 0;
25762 * Returns True if the specified row is selected.
25763 * @param {Number/Record} record The record or index of the record to check
25764 * @return {Boolean}
25766 isSelected : function(index){
25767 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
25768 return (r && this.selections.key(r.id) ? true : false);
25772 * Returns True if the specified record id is selected.
25773 * @param {String} id The id of record to check
25774 * @return {Boolean}
25776 isIdSelected : function(id){
25777 return (this.selections.key(id) ? true : false);
25782 handleMouseDBClick : function(e, t){
25786 handleMouseDown : function(e, t)
25788 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
25789 if(this.isLocked() || rowIndex < 0 ){
25792 if(e.shiftKey && this.last !== false){
25793 var last = this.last;
25794 this.selectRange(last, rowIndex, e.ctrlKey);
25795 this.last = last; // reset the last
25799 var isSelected = this.isSelected(rowIndex);
25800 //Roo.log("select row:" + rowIndex);
25802 this.deselectRow(rowIndex);
25804 this.selectRow(rowIndex, true);
25808 if(e.button !== 0 && isSelected){
25809 alert('rowIndex 2: ' + rowIndex);
25810 view.focusRow(rowIndex);
25811 }else if(e.ctrlKey && isSelected){
25812 this.deselectRow(rowIndex);
25813 }else if(!isSelected){
25814 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
25815 view.focusRow(rowIndex);
25819 this.fireEvent("afterselectionchange", this);
25822 handleDragableRowClick : function(grid, rowIndex, e)
25824 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
25825 this.selectRow(rowIndex, false);
25826 grid.view.focusRow(rowIndex);
25827 this.fireEvent("afterselectionchange", this);
25832 * Selects multiple rows.
25833 * @param {Array} rows Array of the indexes of the row to select
25834 * @param {Boolean} keepExisting (optional) True to keep existing selections
25836 selectRows : function(rows, keepExisting){
25838 this.clearSelections();
25840 for(var i = 0, len = rows.length; i < len; i++){
25841 this.selectRow(rows[i], true);
25846 * Selects a range of rows. All rows in between startRow and endRow are also selected.
25847 * @param {Number} startRow The index of the first row in the range
25848 * @param {Number} endRow The index of the last row in the range
25849 * @param {Boolean} keepExisting (optional) True to retain existing selections
25851 selectRange : function(startRow, endRow, keepExisting){
25856 this.clearSelections();
25858 if(startRow <= endRow){
25859 for(var i = startRow; i <= endRow; i++){
25860 this.selectRow(i, true);
25863 for(var i = startRow; i >= endRow; i--){
25864 this.selectRow(i, true);
25870 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
25871 * @param {Number} startRow The index of the first row in the range
25872 * @param {Number} endRow The index of the last row in the range
25874 deselectRange : function(startRow, endRow, preventViewNotify){
25878 for(var i = startRow; i <= endRow; i++){
25879 this.deselectRow(i, preventViewNotify);
25885 * @param {Number} row The index of the row to select
25886 * @param {Boolean} keepExisting (optional) True to keep existing selections
25888 selectRow : function(index, keepExisting, preventViewNotify)
25890 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
25893 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
25894 if(!keepExisting || this.singleSelect){
25895 this.clearSelections();
25898 var r = this.grid.store.getAt(index);
25899 //console.log('selectRow - record id :' + r.id);
25901 this.selections.add(r);
25902 this.last = this.lastActive = index;
25903 if(!preventViewNotify){
25904 var proxy = new Roo.Element(
25905 this.grid.getRowDom(index)
25907 proxy.addClass('bg-info info');
25909 this.fireEvent("rowselect", this, index, r);
25910 this.fireEvent("selectionchange", this);
25916 * @param {Number} row The index of the row to deselect
25918 deselectRow : function(index, preventViewNotify)
25923 if(this.last == index){
25926 if(this.lastActive == index){
25927 this.lastActive = false;
25930 var r = this.grid.store.getAt(index);
25935 this.selections.remove(r);
25936 //.console.log('deselectRow - record id :' + r.id);
25937 if(!preventViewNotify){
25939 var proxy = new Roo.Element(
25940 this.grid.getRowDom(index)
25942 proxy.removeClass('bg-info info');
25944 this.fireEvent("rowdeselect", this, index);
25945 this.fireEvent("selectionchange", this);
25949 restoreLast : function(){
25951 this.last = this._last;
25956 acceptsNav : function(row, col, cm){
25957 return !cm.isHidden(col) && cm.isCellEditable(col, row);
25961 onEditorKey : function(field, e){
25962 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
25967 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
25969 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
25971 }else if(k == e.ENTER && !e.ctrlKey){
25975 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
25977 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
25979 }else if(k == e.ESC){
25983 g.startEditing(newCell[0], newCell[1]);
25989 * Ext JS Library 1.1.1
25990 * Copyright(c) 2006-2007, Ext JS, LLC.
25992 * Originally Released Under LGPL - original licence link has changed is not relivant.
25995 * <script type="text/javascript">
25999 * @class Roo.bootstrap.PagingToolbar
26000 * @extends Roo.bootstrap.NavSimplebar
26001 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26003 * Create a new PagingToolbar
26004 * @param {Object} config The config object
26005 * @param {Roo.data.Store} store
26007 Roo.bootstrap.PagingToolbar = function(config)
26009 // old args format still supported... - xtype is prefered..
26010 // created from xtype...
26012 this.ds = config.dataSource;
26014 if (config.store && !this.ds) {
26015 this.store= Roo.factory(config.store, Roo.data);
26016 this.ds = this.store;
26017 this.ds.xmodule = this.xmodule || false;
26020 this.toolbarItems = [];
26021 if (config.items) {
26022 this.toolbarItems = config.items;
26025 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
26030 this.bind(this.ds);
26033 if (Roo.bootstrap.version == 4) {
26034 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
26036 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
26041 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
26043 * @cfg {Roo.data.Store} dataSource
26044 * The underlying data store providing the paged data
26047 * @cfg {String/HTMLElement/Element} container
26048 * container The id or element that will contain the toolbar
26051 * @cfg {Boolean} displayInfo
26052 * True to display the displayMsg (defaults to false)
26055 * @cfg {Number} pageSize
26056 * The number of records to display per page (defaults to 20)
26060 * @cfg {String} displayMsg
26061 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26063 displayMsg : 'Displaying {0} - {1} of {2}',
26065 * @cfg {String} emptyMsg
26066 * The message to display when no records are found (defaults to "No data to display")
26068 emptyMsg : 'No data to display',
26070 * Customizable piece of the default paging text (defaults to "Page")
26073 beforePageText : "Page",
26075 * Customizable piece of the default paging text (defaults to "of %0")
26078 afterPageText : "of {0}",
26080 * Customizable piece of the default paging text (defaults to "First Page")
26083 firstText : "First Page",
26085 * Customizable piece of the default paging text (defaults to "Previous Page")
26088 prevText : "Previous Page",
26090 * Customizable piece of the default paging text (defaults to "Next Page")
26093 nextText : "Next Page",
26095 * Customizable piece of the default paging text (defaults to "Last Page")
26098 lastText : "Last Page",
26100 * Customizable piece of the default paging text (defaults to "Refresh")
26103 refreshText : "Refresh",
26107 onRender : function(ct, position)
26109 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
26110 this.navgroup.parentId = this.id;
26111 this.navgroup.onRender(this.el, null);
26112 // add the buttons to the navgroup
26114 if(this.displayInfo){
26115 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
26116 this.displayEl = this.el.select('.x-paging-info', true).first();
26117 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
26118 // this.displayEl = navel.el.select('span',true).first();
26124 Roo.each(_this.buttons, function(e){ // this might need to use render????
26125 Roo.factory(e).render(_this.el);
26129 Roo.each(_this.toolbarItems, function(e) {
26130 _this.navgroup.addItem(e);
26134 this.first = this.navgroup.addItem({
26135 tooltip: this.firstText,
26136 cls: "prev btn-outline-secondary",
26137 html : ' <i class="fa fa-step-backward"></i>',
26139 preventDefault: true,
26140 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
26143 this.prev = this.navgroup.addItem({
26144 tooltip: this.prevText,
26145 cls: "prev btn-outline-secondary",
26146 html : ' <i class="fa fa-backward"></i>',
26148 preventDefault: true,
26149 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
26151 //this.addSeparator();
26154 var field = this.navgroup.addItem( {
26156 cls : 'x-paging-position btn-outline-secondary',
26158 html : this.beforePageText +
26159 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
26160 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
26163 this.field = field.el.select('input', true).first();
26164 this.field.on("keydown", this.onPagingKeydown, this);
26165 this.field.on("focus", function(){this.dom.select();});
26168 this.afterTextEl = field.el.select('.x-paging-after',true).first();
26169 //this.field.setHeight(18);
26170 //this.addSeparator();
26171 this.next = this.navgroup.addItem({
26172 tooltip: this.nextText,
26173 cls: "next btn-outline-secondary",
26174 html : ' <i class="fa fa-forward"></i>',
26176 preventDefault: true,
26177 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
26179 this.last = this.navgroup.addItem({
26180 tooltip: this.lastText,
26181 html : ' <i class="fa fa-step-forward"></i>',
26182 cls: "next btn-outline-secondary",
26184 preventDefault: true,
26185 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
26187 //this.addSeparator();
26188 this.loading = this.navgroup.addItem({
26189 tooltip: this.refreshText,
26190 cls: "btn-outline-secondary",
26191 html : ' <i class="fa fa-refresh"></i>',
26192 preventDefault: true,
26193 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
26199 updateInfo : function(){
26200 if(this.displayEl){
26201 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
26202 var msg = count == 0 ?
26206 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
26208 this.displayEl.update(msg);
26213 onLoad : function(ds, r, o)
26215 this.cursor = o.params.start ? o.params.start : 0;
26217 var d = this.getPageData(),
26222 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
26223 this.field.dom.value = ap;
26224 this.first.setDisabled(ap == 1);
26225 this.prev.setDisabled(ap == 1);
26226 this.next.setDisabled(ap == ps);
26227 this.last.setDisabled(ap == ps);
26228 this.loading.enable();
26233 getPageData : function(){
26234 var total = this.ds.getTotalCount();
26237 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
26238 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
26243 onLoadError : function(){
26244 this.loading.enable();
26248 onPagingKeydown : function(e){
26249 var k = e.getKey();
26250 var d = this.getPageData();
26252 var v = this.field.dom.value, pageNum;
26253 if(!v || isNaN(pageNum = parseInt(v, 10))){
26254 this.field.dom.value = d.activePage;
26257 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
26258 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
26261 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))
26263 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
26264 this.field.dom.value = pageNum;
26265 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
26268 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
26270 var v = this.field.dom.value, pageNum;
26271 var increment = (e.shiftKey) ? 10 : 1;
26272 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
26275 if(!v || isNaN(pageNum = parseInt(v, 10))) {
26276 this.field.dom.value = d.activePage;
26279 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
26281 this.field.dom.value = parseInt(v, 10) + increment;
26282 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
26283 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
26290 beforeLoad : function(){
26292 this.loading.disable();
26297 onClick : function(which){
26306 ds.load({params:{start: 0, limit: this.pageSize}});
26309 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
26312 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
26315 var total = ds.getTotalCount();
26316 var extra = total % this.pageSize;
26317 var lastStart = extra ? (total - extra) : total-this.pageSize;
26318 ds.load({params:{start: lastStart, limit: this.pageSize}});
26321 ds.load({params:{start: this.cursor, limit: this.pageSize}});
26327 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
26328 * @param {Roo.data.Store} store The data store to unbind
26330 unbind : function(ds){
26331 ds.un("beforeload", this.beforeLoad, this);
26332 ds.un("load", this.onLoad, this);
26333 ds.un("loadexception", this.onLoadError, this);
26334 ds.un("remove", this.updateInfo, this);
26335 ds.un("add", this.updateInfo, this);
26336 this.ds = undefined;
26340 * Binds the paging toolbar to the specified {@link Roo.data.Store}
26341 * @param {Roo.data.Store} store The data store to bind
26343 bind : function(ds){
26344 ds.on("beforeload", this.beforeLoad, this);
26345 ds.on("load", this.onLoad, this);
26346 ds.on("loadexception", this.onLoadError, this);
26347 ds.on("remove", this.updateInfo, this);
26348 ds.on("add", this.updateInfo, this);
26359 * @class Roo.bootstrap.MessageBar
26360 * @extends Roo.bootstrap.Component
26361 * Bootstrap MessageBar class
26362 * @cfg {String} html contents of the MessageBar
26363 * @cfg {String} weight (info | success | warning | danger) default info
26364 * @cfg {String} beforeClass insert the bar before the given class
26365 * @cfg {Boolean} closable (true | false) default false
26366 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
26369 * Create a new Element
26370 * @param {Object} config The config object
26373 Roo.bootstrap.MessageBar = function(config){
26374 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
26377 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
26383 beforeClass: 'bootstrap-sticky-wrap',
26385 getAutoCreate : function(){
26389 cls: 'alert alert-dismissable alert-' + this.weight,
26394 html: this.html || ''
26400 cfg.cls += ' alert-messages-fixed';
26414 onRender : function(ct, position)
26416 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
26419 var cfg = Roo.apply({}, this.getAutoCreate());
26423 cfg.cls += ' ' + this.cls;
26426 cfg.style = this.style;
26428 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
26430 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26433 this.el.select('>button.close').on('click', this.hide, this);
26439 if (!this.rendered) {
26445 this.fireEvent('show', this);
26451 if (!this.rendered) {
26457 this.fireEvent('hide', this);
26460 update : function()
26462 // var e = this.el.dom.firstChild;
26464 // if(this.closable){
26465 // e = e.nextSibling;
26468 // e.data = this.html || '';
26470 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
26486 * @class Roo.bootstrap.Graph
26487 * @extends Roo.bootstrap.Component
26488 * Bootstrap Graph class
26492 @cfg {String} graphtype bar | vbar | pie
26493 @cfg {number} g_x coodinator | centre x (pie)
26494 @cfg {number} g_y coodinator | centre y (pie)
26495 @cfg {number} g_r radius (pie)
26496 @cfg {number} g_height height of the chart (respected by all elements in the set)
26497 @cfg {number} g_width width of the chart (respected by all elements in the set)
26498 @cfg {Object} title The title of the chart
26501 -opts (object) options for the chart
26503 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
26504 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
26506 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.
26507 o stacked (boolean) whether or not to tread values as in a stacked bar chart
26509 o stretch (boolean)
26511 -opts (object) options for the pie
26514 o startAngle (number)
26515 o endAngle (number)
26519 * Create a new Input
26520 * @param {Object} config The config object
26523 Roo.bootstrap.Graph = function(config){
26524 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
26530 * The img click event for the img.
26531 * @param {Roo.EventObject} e
26537 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
26548 //g_colors: this.colors,
26555 getAutoCreate : function(){
26566 onRender : function(ct,position){
26569 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
26571 if (typeof(Raphael) == 'undefined') {
26572 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
26576 this.raphael = Raphael(this.el.dom);
26578 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26579 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26580 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
26581 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
26583 r.text(160, 10, "Single Series Chart").attr(txtattr);
26584 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
26585 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
26586 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
26588 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
26589 r.barchart(330, 10, 300, 220, data1);
26590 r.barchart(10, 250, 300, 220, data2, {stacked: true});
26591 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
26594 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
26595 // r.barchart(30, 30, 560, 250, xdata, {
26596 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
26597 // axis : "0 0 1 1",
26598 // axisxlabels : xdata
26599 // //yvalues : cols,
26602 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
26604 // this.load(null,xdata,{
26605 // axis : "0 0 1 1",
26606 // axisxlabels : xdata
26611 load : function(graphtype,xdata,opts)
26613 this.raphael.clear();
26615 graphtype = this.graphtype;
26620 var r = this.raphael,
26621 fin = function () {
26622 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
26624 fout = function () {
26625 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
26627 pfin = function() {
26628 this.sector.stop();
26629 this.sector.scale(1.1, 1.1, this.cx, this.cy);
26632 this.label[0].stop();
26633 this.label[0].attr({ r: 7.5 });
26634 this.label[1].attr({ "font-weight": 800 });
26637 pfout = function() {
26638 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
26641 this.label[0].animate({ r: 5 }, 500, "bounce");
26642 this.label[1].attr({ "font-weight": 400 });
26648 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
26651 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
26654 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
26655 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
26657 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
26664 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
26669 setTitle: function(o)
26674 initEvents: function() {
26677 this.el.on('click', this.onClick, this);
26681 onClick : function(e)
26683 Roo.log('img onclick');
26684 this.fireEvent('click', this, e);
26696 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26699 * @class Roo.bootstrap.dash.NumberBox
26700 * @extends Roo.bootstrap.Component
26701 * Bootstrap NumberBox class
26702 * @cfg {String} headline Box headline
26703 * @cfg {String} content Box content
26704 * @cfg {String} icon Box icon
26705 * @cfg {String} footer Footer text
26706 * @cfg {String} fhref Footer href
26709 * Create a new NumberBox
26710 * @param {Object} config The config object
26714 Roo.bootstrap.dash.NumberBox = function(config){
26715 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
26719 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
26728 getAutoCreate : function(){
26732 cls : 'small-box ',
26740 cls : 'roo-headline',
26741 html : this.headline
26745 cls : 'roo-content',
26746 html : this.content
26760 cls : 'ion ' + this.icon
26769 cls : 'small-box-footer',
26770 href : this.fhref || '#',
26774 cfg.cn.push(footer);
26781 onRender : function(ct,position){
26782 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
26789 setHeadline: function (value)
26791 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
26794 setFooter: function (value, href)
26796 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
26799 this.el.select('a.small-box-footer',true).first().attr('href', href);
26804 setContent: function (value)
26806 this.el.select('.roo-content',true).first().dom.innerHTML = value;
26809 initEvents: function()
26823 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26826 * @class Roo.bootstrap.dash.TabBox
26827 * @extends Roo.bootstrap.Component
26828 * Bootstrap TabBox class
26829 * @cfg {String} title Title of the TabBox
26830 * @cfg {String} icon Icon of the TabBox
26831 * @cfg {Boolean} showtabs (true|false) show the tabs default true
26832 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
26835 * Create a new TabBox
26836 * @param {Object} config The config object
26840 Roo.bootstrap.dash.TabBox = function(config){
26841 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
26846 * When a pane is added
26847 * @param {Roo.bootstrap.dash.TabPane} pane
26851 * @event activatepane
26852 * When a pane is activated
26853 * @param {Roo.bootstrap.dash.TabPane} pane
26855 "activatepane" : true
26863 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
26868 tabScrollable : false,
26870 getChildContainer : function()
26872 return this.el.select('.tab-content', true).first();
26875 getAutoCreate : function(){
26879 cls: 'pull-left header',
26887 cls: 'fa ' + this.icon
26893 cls: 'nav nav-tabs pull-right',
26899 if(this.tabScrollable){
26906 cls: 'nav nav-tabs pull-right',
26917 cls: 'nav-tabs-custom',
26922 cls: 'tab-content no-padding',
26930 initEvents : function()
26932 //Roo.log('add add pane handler');
26933 this.on('addpane', this.onAddPane, this);
26936 * Updates the box title
26937 * @param {String} html to set the title to.
26939 setTitle : function(value)
26941 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
26943 onAddPane : function(pane)
26945 this.panes.push(pane);
26946 //Roo.log('addpane');
26948 // tabs are rendere left to right..
26949 if(!this.showtabs){
26953 var ctr = this.el.select('.nav-tabs', true).first();
26956 var existing = ctr.select('.nav-tab',true);
26957 var qty = existing.getCount();;
26960 var tab = ctr.createChild({
26962 cls : 'nav-tab' + (qty ? '' : ' active'),
26970 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
26973 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
26975 pane.el.addClass('active');
26980 onTabClick : function(ev,un,ob,pane)
26982 //Roo.log('tab - prev default');
26983 ev.preventDefault();
26986 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
26987 pane.tab.addClass('active');
26988 //Roo.log(pane.title);
26989 this.getChildContainer().select('.tab-pane',true).removeClass('active');
26990 // technically we should have a deactivate event.. but maybe add later.
26991 // and it should not de-activate the selected tab...
26992 this.fireEvent('activatepane', pane);
26993 pane.el.addClass('active');
26994 pane.fireEvent('activate');
26999 getActivePane : function()
27002 Roo.each(this.panes, function(p) {
27003 if(p.el.hasClass('active')){
27024 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27026 * @class Roo.bootstrap.TabPane
27027 * @extends Roo.bootstrap.Component
27028 * Bootstrap TabPane class
27029 * @cfg {Boolean} active (false | true) Default false
27030 * @cfg {String} title title of panel
27034 * Create a new TabPane
27035 * @param {Object} config The config object
27038 Roo.bootstrap.dash.TabPane = function(config){
27039 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
27045 * When a pane is activated
27046 * @param {Roo.bootstrap.dash.TabPane} pane
27053 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
27058 // the tabBox that this is attached to.
27061 getAutoCreate : function()
27069 cfg.cls += ' active';
27074 initEvents : function()
27076 //Roo.log('trigger add pane handler');
27077 this.parent().fireEvent('addpane', this)
27081 * Updates the tab title
27082 * @param {String} html to set the title to.
27084 setTitle: function(str)
27090 this.tab.select('a', true).first().dom.innerHTML = str;
27107 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27110 * @class Roo.bootstrap.menu.Menu
27111 * @extends Roo.bootstrap.Component
27112 * Bootstrap Menu class - container for Menu
27113 * @cfg {String} html Text of the menu
27114 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
27115 * @cfg {String} icon Font awesome icon
27116 * @cfg {String} pos Menu align to (top | bottom) default bottom
27120 * Create a new Menu
27121 * @param {Object} config The config object
27125 Roo.bootstrap.menu.Menu = function(config){
27126 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
27130 * @event beforeshow
27131 * Fires before this menu is displayed
27132 * @param {Roo.bootstrap.menu.Menu} this
27136 * @event beforehide
27137 * Fires before this menu is hidden
27138 * @param {Roo.bootstrap.menu.Menu} this
27143 * Fires after this menu is displayed
27144 * @param {Roo.bootstrap.menu.Menu} this
27149 * Fires after this menu is hidden
27150 * @param {Roo.bootstrap.menu.Menu} this
27155 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
27156 * @param {Roo.bootstrap.menu.Menu} this
27157 * @param {Roo.EventObject} e
27164 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
27168 weight : 'default',
27173 getChildContainer : function() {
27174 if(this.isSubMenu){
27178 return this.el.select('ul.dropdown-menu', true).first();
27181 getAutoCreate : function()
27186 cls : 'roo-menu-text',
27194 cls : 'fa ' + this.icon
27205 cls : 'dropdown-button btn btn-' + this.weight,
27210 cls : 'dropdown-toggle btn btn-' + this.weight,
27220 cls : 'dropdown-menu'
27226 if(this.pos == 'top'){
27227 cfg.cls += ' dropup';
27230 if(this.isSubMenu){
27233 cls : 'dropdown-menu'
27240 onRender : function(ct, position)
27242 this.isSubMenu = ct.hasClass('dropdown-submenu');
27244 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
27247 initEvents : function()
27249 if(this.isSubMenu){
27253 this.hidden = true;
27255 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
27256 this.triggerEl.on('click', this.onTriggerPress, this);
27258 this.buttonEl = this.el.select('button.dropdown-button', true).first();
27259 this.buttonEl.on('click', this.onClick, this);
27265 if(this.isSubMenu){
27269 return this.el.select('ul.dropdown-menu', true).first();
27272 onClick : function(e)
27274 this.fireEvent("click", this, e);
27277 onTriggerPress : function(e)
27279 if (this.isVisible()) {
27286 isVisible : function(){
27287 return !this.hidden;
27292 this.fireEvent("beforeshow", this);
27294 this.hidden = false;
27295 this.el.addClass('open');
27297 Roo.get(document).on("mouseup", this.onMouseUp, this);
27299 this.fireEvent("show", this);
27306 this.fireEvent("beforehide", this);
27308 this.hidden = true;
27309 this.el.removeClass('open');
27311 Roo.get(document).un("mouseup", this.onMouseUp);
27313 this.fireEvent("hide", this);
27316 onMouseUp : function()
27330 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27333 * @class Roo.bootstrap.menu.Item
27334 * @extends Roo.bootstrap.Component
27335 * Bootstrap MenuItem class
27336 * @cfg {Boolean} submenu (true | false) default false
27337 * @cfg {String} html text of the item
27338 * @cfg {String} href the link
27339 * @cfg {Boolean} disable (true | false) default false
27340 * @cfg {Boolean} preventDefault (true | false) default true
27341 * @cfg {String} icon Font awesome icon
27342 * @cfg {String} pos Submenu align to (left | right) default right
27346 * Create a new Item
27347 * @param {Object} config The config object
27351 Roo.bootstrap.menu.Item = function(config){
27352 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
27356 * Fires when the mouse is hovering over this menu
27357 * @param {Roo.bootstrap.menu.Item} this
27358 * @param {Roo.EventObject} e
27363 * Fires when the mouse exits this menu
27364 * @param {Roo.bootstrap.menu.Item} this
27365 * @param {Roo.EventObject} e
27371 * The raw click event for the entire grid.
27372 * @param {Roo.EventObject} e
27378 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
27383 preventDefault: true,
27388 getAutoCreate : function()
27393 cls : 'roo-menu-item-text',
27401 cls : 'fa ' + this.icon
27410 href : this.href || '#',
27417 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
27421 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
27423 if(this.pos == 'left'){
27424 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
27431 initEvents : function()
27433 this.el.on('mouseover', this.onMouseOver, this);
27434 this.el.on('mouseout', this.onMouseOut, this);
27436 this.el.select('a', true).first().on('click', this.onClick, this);
27440 onClick : function(e)
27442 if(this.preventDefault){
27443 e.preventDefault();
27446 this.fireEvent("click", this, e);
27449 onMouseOver : function(e)
27451 if(this.submenu && this.pos == 'left'){
27452 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
27455 this.fireEvent("mouseover", this, e);
27458 onMouseOut : function(e)
27460 this.fireEvent("mouseout", this, e);
27472 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27475 * @class Roo.bootstrap.menu.Separator
27476 * @extends Roo.bootstrap.Component
27477 * Bootstrap Separator class
27480 * Create a new Separator
27481 * @param {Object} config The config object
27485 Roo.bootstrap.menu.Separator = function(config){
27486 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
27489 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
27491 getAutoCreate : function(){
27512 * @class Roo.bootstrap.Tooltip
27513 * Bootstrap Tooltip class
27514 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
27515 * to determine which dom element triggers the tooltip.
27517 * It needs to add support for additional attributes like tooltip-position
27520 * Create a new Toolti
27521 * @param {Object} config The config object
27524 Roo.bootstrap.Tooltip = function(config){
27525 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
27527 this.alignment = Roo.bootstrap.Tooltip.alignment;
27529 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
27530 this.alignment = config.alignment;
27535 Roo.apply(Roo.bootstrap.Tooltip, {
27537 * @function init initialize tooltip monitoring.
27541 currentTip : false,
27542 currentRegion : false,
27548 Roo.get(document).on('mouseover', this.enter ,this);
27549 Roo.get(document).on('mouseout', this.leave, this);
27552 this.currentTip = new Roo.bootstrap.Tooltip();
27555 enter : function(ev)
27557 var dom = ev.getTarget();
27559 //Roo.log(['enter',dom]);
27560 var el = Roo.fly(dom);
27561 if (this.currentEl) {
27563 //Roo.log(this.currentEl);
27564 //Roo.log(this.currentEl.contains(dom));
27565 if (this.currentEl == el) {
27568 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
27574 if (this.currentTip.el) {
27575 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
27579 if(!el || el.dom == document){
27585 // you can not look for children, as if el is the body.. then everythign is the child..
27586 if (!el.attr('tooltip')) { //
27587 if (!el.select("[tooltip]").elements.length) {
27590 // is the mouse over this child...?
27591 bindEl = el.select("[tooltip]").first();
27592 var xy = ev.getXY();
27593 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
27594 //Roo.log("not in region.");
27597 //Roo.log("child element over..");
27600 this.currentEl = bindEl;
27601 this.currentTip.bind(bindEl);
27602 this.currentRegion = Roo.lib.Region.getRegion(dom);
27603 this.currentTip.enter();
27606 leave : function(ev)
27608 var dom = ev.getTarget();
27609 //Roo.log(['leave',dom]);
27610 if (!this.currentEl) {
27615 if (dom != this.currentEl.dom) {
27618 var xy = ev.getXY();
27619 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
27622 // only activate leave if mouse cursor is outside... bounding box..
27627 if (this.currentTip) {
27628 this.currentTip.leave();
27630 //Roo.log('clear currentEl');
27631 this.currentEl = false;
27636 'left' : ['r-l', [-2,0], 'right'],
27637 'right' : ['l-r', [2,0], 'left'],
27638 'bottom' : ['t-b', [0,2], 'top'],
27639 'top' : [ 'b-t', [0,-2], 'bottom']
27645 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
27650 delay : null, // can be { show : 300 , hide: 500}
27654 hoverState : null, //???
27656 placement : 'bottom',
27660 getAutoCreate : function(){
27667 cls : 'tooltip-arrow'
27670 cls : 'tooltip-inner'
27677 bind : function(el)
27683 enter : function () {
27685 if (this.timeout != null) {
27686 clearTimeout(this.timeout);
27689 this.hoverState = 'in';
27690 //Roo.log("enter - show");
27691 if (!this.delay || !this.delay.show) {
27696 this.timeout = setTimeout(function () {
27697 if (_t.hoverState == 'in') {
27700 }, this.delay.show);
27704 clearTimeout(this.timeout);
27706 this.hoverState = 'out';
27707 if (!this.delay || !this.delay.hide) {
27713 this.timeout = setTimeout(function () {
27714 //Roo.log("leave - timeout");
27716 if (_t.hoverState == 'out') {
27718 Roo.bootstrap.Tooltip.currentEl = false;
27723 show : function (msg)
27726 this.render(document.body);
27729 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
27731 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
27733 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
27735 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
27737 var placement = typeof this.placement == 'function' ?
27738 this.placement.call(this, this.el, on_el) :
27741 var autoToken = /\s?auto?\s?/i;
27742 var autoPlace = autoToken.test(placement);
27744 placement = placement.replace(autoToken, '') || 'top';
27748 //this.el.setXY([0,0]);
27750 //this.el.dom.style.display='block';
27752 //this.el.appendTo(on_el);
27754 var p = this.getPosition();
27755 var box = this.el.getBox();
27761 var align = this.alignment[placement];
27763 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
27765 if(placement == 'top' || placement == 'bottom'){
27767 placement = 'right';
27770 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
27771 placement = 'left';
27774 var scroll = Roo.select('body', true).first().getScroll();
27776 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
27780 align = this.alignment[placement];
27783 this.el.alignTo(this.bindEl, align[0],align[1]);
27784 //var arrow = this.el.select('.arrow',true).first();
27785 //arrow.set(align[2],
27787 this.el.addClass(placement);
27789 this.el.addClass('in fade');
27791 this.hoverState = null;
27793 if (this.el.hasClass('fade')) {
27804 //this.el.setXY([0,0]);
27805 this.el.removeClass('in');
27821 * @class Roo.bootstrap.LocationPicker
27822 * @extends Roo.bootstrap.Component
27823 * Bootstrap LocationPicker class
27824 * @cfg {Number} latitude Position when init default 0
27825 * @cfg {Number} longitude Position when init default 0
27826 * @cfg {Number} zoom default 15
27827 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
27828 * @cfg {Boolean} mapTypeControl default false
27829 * @cfg {Boolean} disableDoubleClickZoom default false
27830 * @cfg {Boolean} scrollwheel default true
27831 * @cfg {Boolean} streetViewControl default false
27832 * @cfg {Number} radius default 0
27833 * @cfg {String} locationName
27834 * @cfg {Boolean} draggable default true
27835 * @cfg {Boolean} enableAutocomplete default false
27836 * @cfg {Boolean} enableReverseGeocode default true
27837 * @cfg {String} markerTitle
27840 * Create a new LocationPicker
27841 * @param {Object} config The config object
27845 Roo.bootstrap.LocationPicker = function(config){
27847 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
27852 * Fires when the picker initialized.
27853 * @param {Roo.bootstrap.LocationPicker} this
27854 * @param {Google Location} location
27858 * @event positionchanged
27859 * Fires when the picker position changed.
27860 * @param {Roo.bootstrap.LocationPicker} this
27861 * @param {Google Location} location
27863 positionchanged : true,
27866 * Fires when the map resize.
27867 * @param {Roo.bootstrap.LocationPicker} this
27872 * Fires when the map show.
27873 * @param {Roo.bootstrap.LocationPicker} this
27878 * Fires when the map hide.
27879 * @param {Roo.bootstrap.LocationPicker} this
27884 * Fires when click the map.
27885 * @param {Roo.bootstrap.LocationPicker} this
27886 * @param {Map event} e
27890 * @event mapRightClick
27891 * Fires when right click the map.
27892 * @param {Roo.bootstrap.LocationPicker} this
27893 * @param {Map event} e
27895 mapRightClick : true,
27897 * @event markerClick
27898 * Fires when click the marker.
27899 * @param {Roo.bootstrap.LocationPicker} this
27900 * @param {Map event} e
27902 markerClick : true,
27904 * @event markerRightClick
27905 * Fires when right click the marker.
27906 * @param {Roo.bootstrap.LocationPicker} this
27907 * @param {Map event} e
27909 markerRightClick : true,
27911 * @event OverlayViewDraw
27912 * Fires when OverlayView Draw
27913 * @param {Roo.bootstrap.LocationPicker} this
27915 OverlayViewDraw : true,
27917 * @event OverlayViewOnAdd
27918 * Fires when OverlayView Draw
27919 * @param {Roo.bootstrap.LocationPicker} this
27921 OverlayViewOnAdd : true,
27923 * @event OverlayViewOnRemove
27924 * Fires when OverlayView Draw
27925 * @param {Roo.bootstrap.LocationPicker} this
27927 OverlayViewOnRemove : true,
27929 * @event OverlayViewShow
27930 * Fires when OverlayView Draw
27931 * @param {Roo.bootstrap.LocationPicker} this
27932 * @param {Pixel} cpx
27934 OverlayViewShow : true,
27936 * @event OverlayViewHide
27937 * Fires when OverlayView Draw
27938 * @param {Roo.bootstrap.LocationPicker} this
27940 OverlayViewHide : true,
27942 * @event loadexception
27943 * Fires when load google lib failed.
27944 * @param {Roo.bootstrap.LocationPicker} this
27946 loadexception : true
27951 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
27953 gMapContext: false,
27959 mapTypeControl: false,
27960 disableDoubleClickZoom: false,
27962 streetViewControl: false,
27966 enableAutocomplete: false,
27967 enableReverseGeocode: true,
27970 getAutoCreate: function()
27975 cls: 'roo-location-picker'
27981 initEvents: function(ct, position)
27983 if(!this.el.getWidth() || this.isApplied()){
27987 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27992 initial: function()
27994 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
27995 this.fireEvent('loadexception', this);
27999 if(!this.mapTypeId){
28000 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
28003 this.gMapContext = this.GMapContext();
28005 this.initOverlayView();
28007 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
28011 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
28012 _this.setPosition(_this.gMapContext.marker.position);
28015 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
28016 _this.fireEvent('mapClick', this, event);
28020 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
28021 _this.fireEvent('mapRightClick', this, event);
28025 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
28026 _this.fireEvent('markerClick', this, event);
28030 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
28031 _this.fireEvent('markerRightClick', this, event);
28035 this.setPosition(this.gMapContext.location);
28037 this.fireEvent('initial', this, this.gMapContext.location);
28040 initOverlayView: function()
28044 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
28048 _this.fireEvent('OverlayViewDraw', _this);
28053 _this.fireEvent('OverlayViewOnAdd', _this);
28056 onRemove: function()
28058 _this.fireEvent('OverlayViewOnRemove', _this);
28061 show: function(cpx)
28063 _this.fireEvent('OverlayViewShow', _this, cpx);
28068 _this.fireEvent('OverlayViewHide', _this);
28074 fromLatLngToContainerPixel: function(event)
28076 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
28079 isApplied: function()
28081 return this.getGmapContext() == false ? false : true;
28084 getGmapContext: function()
28086 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
28089 GMapContext: function()
28091 var position = new google.maps.LatLng(this.latitude, this.longitude);
28093 var _map = new google.maps.Map(this.el.dom, {
28096 mapTypeId: this.mapTypeId,
28097 mapTypeControl: this.mapTypeControl,
28098 disableDoubleClickZoom: this.disableDoubleClickZoom,
28099 scrollwheel: this.scrollwheel,
28100 streetViewControl: this.streetViewControl,
28101 locationName: this.locationName,
28102 draggable: this.draggable,
28103 enableAutocomplete: this.enableAutocomplete,
28104 enableReverseGeocode: this.enableReverseGeocode
28107 var _marker = new google.maps.Marker({
28108 position: position,
28110 title: this.markerTitle,
28111 draggable: this.draggable
28118 location: position,
28119 radius: this.radius,
28120 locationName: this.locationName,
28121 addressComponents: {
28122 formatted_address: null,
28123 addressLine1: null,
28124 addressLine2: null,
28126 streetNumber: null,
28130 stateOrProvince: null
28133 domContainer: this.el.dom,
28134 geodecoder: new google.maps.Geocoder()
28138 drawCircle: function(center, radius, options)
28140 if (this.gMapContext.circle != null) {
28141 this.gMapContext.circle.setMap(null);
28145 options = Roo.apply({}, options, {
28146 strokeColor: "#0000FF",
28147 strokeOpacity: .35,
28149 fillColor: "#0000FF",
28153 options.map = this.gMapContext.map;
28154 options.radius = radius;
28155 options.center = center;
28156 this.gMapContext.circle = new google.maps.Circle(options);
28157 return this.gMapContext.circle;
28163 setPosition: function(location)
28165 this.gMapContext.location = location;
28166 this.gMapContext.marker.setPosition(location);
28167 this.gMapContext.map.panTo(location);
28168 this.drawCircle(location, this.gMapContext.radius, {});
28172 if (this.gMapContext.settings.enableReverseGeocode) {
28173 this.gMapContext.geodecoder.geocode({
28174 latLng: this.gMapContext.location
28175 }, function(results, status) {
28177 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
28178 _this.gMapContext.locationName = results[0].formatted_address;
28179 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
28181 _this.fireEvent('positionchanged', this, location);
28188 this.fireEvent('positionchanged', this, location);
28193 google.maps.event.trigger(this.gMapContext.map, "resize");
28195 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
28197 this.fireEvent('resize', this);
28200 setPositionByLatLng: function(latitude, longitude)
28202 this.setPosition(new google.maps.LatLng(latitude, longitude));
28205 getCurrentPosition: function()
28208 latitude: this.gMapContext.location.lat(),
28209 longitude: this.gMapContext.location.lng()
28213 getAddressName: function()
28215 return this.gMapContext.locationName;
28218 getAddressComponents: function()
28220 return this.gMapContext.addressComponents;
28223 address_component_from_google_geocode: function(address_components)
28227 for (var i = 0; i < address_components.length; i++) {
28228 var component = address_components[i];
28229 if (component.types.indexOf("postal_code") >= 0) {
28230 result.postalCode = component.short_name;
28231 } else if (component.types.indexOf("street_number") >= 0) {
28232 result.streetNumber = component.short_name;
28233 } else if (component.types.indexOf("route") >= 0) {
28234 result.streetName = component.short_name;
28235 } else if (component.types.indexOf("neighborhood") >= 0) {
28236 result.city = component.short_name;
28237 } else if (component.types.indexOf("locality") >= 0) {
28238 result.city = component.short_name;
28239 } else if (component.types.indexOf("sublocality") >= 0) {
28240 result.district = component.short_name;
28241 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
28242 result.stateOrProvince = component.short_name;
28243 } else if (component.types.indexOf("country") >= 0) {
28244 result.country = component.short_name;
28248 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
28249 result.addressLine2 = "";
28253 setZoomLevel: function(zoom)
28255 this.gMapContext.map.setZoom(zoom);
28268 this.fireEvent('show', this);
28279 this.fireEvent('hide', this);
28284 Roo.apply(Roo.bootstrap.LocationPicker, {
28286 OverlayView : function(map, options)
28288 options = options || {};
28295 * @class Roo.bootstrap.Alert
28296 * @extends Roo.bootstrap.Component
28297 * Bootstrap Alert class - shows an alert area box
28299 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
28300 Enter a valid email address
28303 * @cfg {String} title The title of alert
28304 * @cfg {String} html The content of alert
28305 * @cfg {String} weight ( success | info | warning | danger )
28306 * @cfg {String} faicon font-awesomeicon
28309 * Create a new alert
28310 * @param {Object} config The config object
28314 Roo.bootstrap.Alert = function(config){
28315 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
28319 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
28326 getAutoCreate : function()
28335 cls : 'roo-alert-icon'
28340 cls : 'roo-alert-title',
28345 cls : 'roo-alert-text',
28352 cfg.cn[0].cls += ' fa ' + this.faicon;
28356 cfg.cls += ' alert-' + this.weight;
28362 initEvents: function()
28364 this.el.setVisibilityMode(Roo.Element.DISPLAY);
28367 setTitle : function(str)
28369 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
28372 setText : function(str)
28374 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
28377 setWeight : function(weight)
28380 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
28383 this.weight = weight;
28385 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
28388 setIcon : function(icon)
28391 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
28394 this.faicon = icon;
28396 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
28417 * @class Roo.bootstrap.UploadCropbox
28418 * @extends Roo.bootstrap.Component
28419 * Bootstrap UploadCropbox class
28420 * @cfg {String} emptyText show when image has been loaded
28421 * @cfg {String} rotateNotify show when image too small to rotate
28422 * @cfg {Number} errorTimeout default 3000
28423 * @cfg {Number} minWidth default 300
28424 * @cfg {Number} minHeight default 300
28425 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
28426 * @cfg {Boolean} isDocument (true|false) default false
28427 * @cfg {String} url action url
28428 * @cfg {String} paramName default 'imageUpload'
28429 * @cfg {String} method default POST
28430 * @cfg {Boolean} loadMask (true|false) default true
28431 * @cfg {Boolean} loadingText default 'Loading...'
28434 * Create a new UploadCropbox
28435 * @param {Object} config The config object
28438 Roo.bootstrap.UploadCropbox = function(config){
28439 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
28443 * @event beforeselectfile
28444 * Fire before select file
28445 * @param {Roo.bootstrap.UploadCropbox} this
28447 "beforeselectfile" : true,
28450 * Fire after initEvent
28451 * @param {Roo.bootstrap.UploadCropbox} this
28456 * Fire after initEvent
28457 * @param {Roo.bootstrap.UploadCropbox} this
28458 * @param {String} data
28463 * Fire when preparing the file data
28464 * @param {Roo.bootstrap.UploadCropbox} this
28465 * @param {Object} file
28470 * Fire when get exception
28471 * @param {Roo.bootstrap.UploadCropbox} this
28472 * @param {XMLHttpRequest} xhr
28474 "exception" : true,
28476 * @event beforeloadcanvas
28477 * Fire before load the canvas
28478 * @param {Roo.bootstrap.UploadCropbox} this
28479 * @param {String} src
28481 "beforeloadcanvas" : true,
28484 * Fire when trash image
28485 * @param {Roo.bootstrap.UploadCropbox} this
28490 * Fire when download the image
28491 * @param {Roo.bootstrap.UploadCropbox} this
28495 * @event footerbuttonclick
28496 * Fire when footerbuttonclick
28497 * @param {Roo.bootstrap.UploadCropbox} this
28498 * @param {String} type
28500 "footerbuttonclick" : true,
28504 * @param {Roo.bootstrap.UploadCropbox} this
28509 * Fire when rotate the image
28510 * @param {Roo.bootstrap.UploadCropbox} this
28511 * @param {String} pos
28516 * Fire when inspect the file
28517 * @param {Roo.bootstrap.UploadCropbox} this
28518 * @param {Object} file
28523 * Fire when xhr upload the file
28524 * @param {Roo.bootstrap.UploadCropbox} this
28525 * @param {Object} data
28530 * Fire when arrange the file data
28531 * @param {Roo.bootstrap.UploadCropbox} this
28532 * @param {Object} formData
28537 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
28540 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
28542 emptyText : 'Click to upload image',
28543 rotateNotify : 'Image is too small to rotate',
28544 errorTimeout : 3000,
28558 cropType : 'image/jpeg',
28560 canvasLoaded : false,
28561 isDocument : false,
28563 paramName : 'imageUpload',
28565 loadingText : 'Loading...',
28568 getAutoCreate : function()
28572 cls : 'roo-upload-cropbox',
28576 cls : 'roo-upload-cropbox-selector',
28581 cls : 'roo-upload-cropbox-body',
28582 style : 'cursor:pointer',
28586 cls : 'roo-upload-cropbox-preview'
28590 cls : 'roo-upload-cropbox-thumb'
28594 cls : 'roo-upload-cropbox-empty-notify',
28595 html : this.emptyText
28599 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
28600 html : this.rotateNotify
28606 cls : 'roo-upload-cropbox-footer',
28609 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
28619 onRender : function(ct, position)
28621 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
28623 if (this.buttons.length) {
28625 Roo.each(this.buttons, function(bb) {
28627 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
28629 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
28635 this.maskEl = this.el;
28639 initEvents : function()
28641 this.urlAPI = (window.createObjectURL && window) ||
28642 (window.URL && URL.revokeObjectURL && URL) ||
28643 (window.webkitURL && webkitURL);
28645 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
28646 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28648 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
28649 this.selectorEl.hide();
28651 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
28652 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28654 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
28655 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28656 this.thumbEl.hide();
28658 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
28659 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28661 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
28662 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28663 this.errorEl.hide();
28665 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
28666 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28667 this.footerEl.hide();
28669 this.setThumbBoxSize();
28675 this.fireEvent('initial', this);
28682 window.addEventListener("resize", function() { _this.resize(); } );
28684 this.bodyEl.on('click', this.beforeSelectFile, this);
28687 this.bodyEl.on('touchstart', this.onTouchStart, this);
28688 this.bodyEl.on('touchmove', this.onTouchMove, this);
28689 this.bodyEl.on('touchend', this.onTouchEnd, this);
28693 this.bodyEl.on('mousedown', this.onMouseDown, this);
28694 this.bodyEl.on('mousemove', this.onMouseMove, this);
28695 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
28696 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
28697 Roo.get(document).on('mouseup', this.onMouseUp, this);
28700 this.selectorEl.on('change', this.onFileSelected, this);
28706 this.baseScale = 1;
28708 this.baseRotate = 1;
28709 this.dragable = false;
28710 this.pinching = false;
28713 this.cropData = false;
28714 this.notifyEl.dom.innerHTML = this.emptyText;
28716 this.selectorEl.dom.value = '';
28720 resize : function()
28722 if(this.fireEvent('resize', this) != false){
28723 this.setThumbBoxPosition();
28724 this.setCanvasPosition();
28728 onFooterButtonClick : function(e, el, o, type)
28731 case 'rotate-left' :
28732 this.onRotateLeft(e);
28734 case 'rotate-right' :
28735 this.onRotateRight(e);
28738 this.beforeSelectFile(e);
28753 this.fireEvent('footerbuttonclick', this, type);
28756 beforeSelectFile : function(e)
28758 e.preventDefault();
28760 if(this.fireEvent('beforeselectfile', this) != false){
28761 this.selectorEl.dom.click();
28765 onFileSelected : function(e)
28767 e.preventDefault();
28769 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28773 var file = this.selectorEl.dom.files[0];
28775 if(this.fireEvent('inspect', this, file) != false){
28776 this.prepare(file);
28781 trash : function(e)
28783 this.fireEvent('trash', this);
28786 download : function(e)
28788 this.fireEvent('download', this);
28791 loadCanvas : function(src)
28793 if(this.fireEvent('beforeloadcanvas', this, src) != false){
28797 this.imageEl = document.createElement('img');
28801 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
28803 this.imageEl.src = src;
28807 onLoadCanvas : function()
28809 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
28810 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
28812 this.bodyEl.un('click', this.beforeSelectFile, this);
28814 this.notifyEl.hide();
28815 this.thumbEl.show();
28816 this.footerEl.show();
28818 this.baseRotateLevel();
28820 if(this.isDocument){
28821 this.setThumbBoxSize();
28824 this.setThumbBoxPosition();
28826 this.baseScaleLevel();
28832 this.canvasLoaded = true;
28835 this.maskEl.unmask();
28840 setCanvasPosition : function()
28842 if(!this.canvasEl){
28846 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
28847 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
28849 this.previewEl.setLeft(pw);
28850 this.previewEl.setTop(ph);
28854 onMouseDown : function(e)
28858 this.dragable = true;
28859 this.pinching = false;
28861 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
28862 this.dragable = false;
28866 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28867 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28871 onMouseMove : function(e)
28875 if(!this.canvasLoaded){
28879 if (!this.dragable){
28883 var minX = Math.ceil(this.thumbEl.getLeft(true));
28884 var minY = Math.ceil(this.thumbEl.getTop(true));
28886 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
28887 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
28889 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28890 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28892 x = x - this.mouseX;
28893 y = y - this.mouseY;
28895 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
28896 var bgY = Math.ceil(y + this.previewEl.getTop(true));
28898 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
28899 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
28901 this.previewEl.setLeft(bgX);
28902 this.previewEl.setTop(bgY);
28904 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
28905 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
28908 onMouseUp : function(e)
28912 this.dragable = false;
28915 onMouseWheel : function(e)
28919 this.startScale = this.scale;
28921 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
28923 if(!this.zoomable()){
28924 this.scale = this.startScale;
28933 zoomable : function()
28935 var minScale = this.thumbEl.getWidth() / this.minWidth;
28937 if(this.minWidth < this.minHeight){
28938 minScale = this.thumbEl.getHeight() / this.minHeight;
28941 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
28942 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
28946 (this.rotate == 0 || this.rotate == 180) &&
28948 width > this.imageEl.OriginWidth ||
28949 height > this.imageEl.OriginHeight ||
28950 (width < this.minWidth && height < this.minHeight)
28958 (this.rotate == 90 || this.rotate == 270) &&
28960 width > this.imageEl.OriginWidth ||
28961 height > this.imageEl.OriginHeight ||
28962 (width < this.minHeight && height < this.minWidth)
28969 !this.isDocument &&
28970 (this.rotate == 0 || this.rotate == 180) &&
28972 width < this.minWidth ||
28973 width > this.imageEl.OriginWidth ||
28974 height < this.minHeight ||
28975 height > this.imageEl.OriginHeight
28982 !this.isDocument &&
28983 (this.rotate == 90 || this.rotate == 270) &&
28985 width < this.minHeight ||
28986 width > this.imageEl.OriginWidth ||
28987 height < this.minWidth ||
28988 height > this.imageEl.OriginHeight
28998 onRotateLeft : function(e)
29000 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29002 var minScale = this.thumbEl.getWidth() / this.minWidth;
29004 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29005 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29007 this.startScale = this.scale;
29009 while (this.getScaleLevel() < minScale){
29011 this.scale = this.scale + 1;
29013 if(!this.zoomable()){
29018 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29019 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29024 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29031 this.scale = this.startScale;
29033 this.onRotateFail();
29038 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29040 if(this.isDocument){
29041 this.setThumbBoxSize();
29042 this.setThumbBoxPosition();
29043 this.setCanvasPosition();
29048 this.fireEvent('rotate', this, 'left');
29052 onRotateRight : function(e)
29054 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29056 var minScale = this.thumbEl.getWidth() / this.minWidth;
29058 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29059 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29061 this.startScale = this.scale;
29063 while (this.getScaleLevel() < minScale){
29065 this.scale = this.scale + 1;
29067 if(!this.zoomable()){
29072 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29073 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29078 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29085 this.scale = this.startScale;
29087 this.onRotateFail();
29092 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29094 if(this.isDocument){
29095 this.setThumbBoxSize();
29096 this.setThumbBoxPosition();
29097 this.setCanvasPosition();
29102 this.fireEvent('rotate', this, 'right');
29105 onRotateFail : function()
29107 this.errorEl.show(true);
29111 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
29116 this.previewEl.dom.innerHTML = '';
29118 var canvasEl = document.createElement("canvas");
29120 var contextEl = canvasEl.getContext("2d");
29122 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29123 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29124 var center = this.imageEl.OriginWidth / 2;
29126 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
29127 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29128 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29129 center = this.imageEl.OriginHeight / 2;
29132 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
29134 contextEl.translate(center, center);
29135 contextEl.rotate(this.rotate * Math.PI / 180);
29137 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29139 this.canvasEl = document.createElement("canvas");
29141 this.contextEl = this.canvasEl.getContext("2d");
29143 switch (this.rotate) {
29146 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29147 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29149 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29154 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29155 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29157 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29158 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);
29162 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29167 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29168 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29170 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29171 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);
29175 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);
29180 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29181 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29183 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29184 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29188 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);
29195 this.previewEl.appendChild(this.canvasEl);
29197 this.setCanvasPosition();
29202 if(!this.canvasLoaded){
29206 var imageCanvas = document.createElement("canvas");
29208 var imageContext = imageCanvas.getContext("2d");
29210 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29211 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29213 var center = imageCanvas.width / 2;
29215 imageContext.translate(center, center);
29217 imageContext.rotate(this.rotate * Math.PI / 180);
29219 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29221 var canvas = document.createElement("canvas");
29223 var context = canvas.getContext("2d");
29225 canvas.width = this.minWidth;
29226 canvas.height = this.minHeight;
29228 switch (this.rotate) {
29231 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
29232 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
29234 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29235 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29237 var targetWidth = this.minWidth - 2 * x;
29238 var targetHeight = this.minHeight - 2 * y;
29242 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29243 scale = targetWidth / width;
29246 if(x > 0 && y == 0){
29247 scale = targetHeight / height;
29250 if(x > 0 && y > 0){
29251 scale = targetWidth / width;
29253 if(width < height){
29254 scale = targetHeight / height;
29258 context.scale(scale, scale);
29260 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29261 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29263 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29264 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29266 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29271 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
29272 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
29274 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29275 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29277 var targetWidth = this.minWidth - 2 * x;
29278 var targetHeight = this.minHeight - 2 * y;
29282 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29283 scale = targetWidth / width;
29286 if(x > 0 && y == 0){
29287 scale = targetHeight / height;
29290 if(x > 0 && y > 0){
29291 scale = targetWidth / width;
29293 if(width < height){
29294 scale = targetHeight / height;
29298 context.scale(scale, scale);
29300 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29301 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29303 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29304 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29306 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
29308 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29313 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
29314 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
29316 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29317 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29319 var targetWidth = this.minWidth - 2 * x;
29320 var targetHeight = this.minHeight - 2 * y;
29324 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29325 scale = targetWidth / width;
29328 if(x > 0 && y == 0){
29329 scale = targetHeight / height;
29332 if(x > 0 && y > 0){
29333 scale = targetWidth / width;
29335 if(width < height){
29336 scale = targetHeight / height;
29340 context.scale(scale, scale);
29342 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29343 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29345 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29346 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29348 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
29349 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
29351 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29356 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
29357 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
29359 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
29360 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
29362 var targetWidth = this.minWidth - 2 * x;
29363 var targetHeight = this.minHeight - 2 * y;
29367 if((x == 0 && y == 0) || (x == 0 && y > 0)){
29368 scale = targetWidth / width;
29371 if(x > 0 && y == 0){
29372 scale = targetHeight / height;
29375 if(x > 0 && y > 0){
29376 scale = targetWidth / width;
29378 if(width < height){
29379 scale = targetHeight / height;
29383 context.scale(scale, scale);
29385 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
29386 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
29388 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
29389 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
29391 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
29393 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
29400 this.cropData = canvas.toDataURL(this.cropType);
29402 if(this.fireEvent('crop', this, this.cropData) !== false){
29403 this.process(this.file, this.cropData);
29410 setThumbBoxSize : function()
29414 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
29415 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
29416 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
29418 this.minWidth = width;
29419 this.minHeight = height;
29421 if(this.rotate == 90 || this.rotate == 270){
29422 this.minWidth = height;
29423 this.minHeight = width;
29428 width = Math.ceil(this.minWidth * height / this.minHeight);
29430 if(this.minWidth > this.minHeight){
29432 height = Math.ceil(this.minHeight * width / this.minWidth);
29435 this.thumbEl.setStyle({
29436 width : width + 'px',
29437 height : height + 'px'
29444 setThumbBoxPosition : function()
29446 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
29447 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
29449 this.thumbEl.setLeft(x);
29450 this.thumbEl.setTop(y);
29454 baseRotateLevel : function()
29456 this.baseRotate = 1;
29459 typeof(this.exif) != 'undefined' &&
29460 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
29461 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
29463 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
29466 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
29470 baseScaleLevel : function()
29474 if(this.isDocument){
29476 if(this.baseRotate == 6 || this.baseRotate == 8){
29478 height = this.thumbEl.getHeight();
29479 this.baseScale = height / this.imageEl.OriginWidth;
29481 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
29482 width = this.thumbEl.getWidth();
29483 this.baseScale = width / this.imageEl.OriginHeight;
29489 height = this.thumbEl.getHeight();
29490 this.baseScale = height / this.imageEl.OriginHeight;
29492 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
29493 width = this.thumbEl.getWidth();
29494 this.baseScale = width / this.imageEl.OriginWidth;
29500 if(this.baseRotate == 6 || this.baseRotate == 8){
29502 width = this.thumbEl.getHeight();
29503 this.baseScale = width / this.imageEl.OriginHeight;
29505 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
29506 height = this.thumbEl.getWidth();
29507 this.baseScale = height / this.imageEl.OriginHeight;
29510 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29511 height = this.thumbEl.getWidth();
29512 this.baseScale = height / this.imageEl.OriginHeight;
29514 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
29515 width = this.thumbEl.getHeight();
29516 this.baseScale = width / this.imageEl.OriginWidth;
29523 width = this.thumbEl.getWidth();
29524 this.baseScale = width / this.imageEl.OriginWidth;
29526 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
29527 height = this.thumbEl.getHeight();
29528 this.baseScale = height / this.imageEl.OriginHeight;
29531 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29533 height = this.thumbEl.getHeight();
29534 this.baseScale = height / this.imageEl.OriginHeight;
29536 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
29537 width = this.thumbEl.getWidth();
29538 this.baseScale = width / this.imageEl.OriginWidth;
29546 getScaleLevel : function()
29548 return this.baseScale * Math.pow(1.1, this.scale);
29551 onTouchStart : function(e)
29553 if(!this.canvasLoaded){
29554 this.beforeSelectFile(e);
29558 var touches = e.browserEvent.touches;
29564 if(touches.length == 1){
29565 this.onMouseDown(e);
29569 if(touches.length != 2){
29575 for(var i = 0, finger; finger = touches[i]; i++){
29576 coords.push(finger.pageX, finger.pageY);
29579 var x = Math.pow(coords[0] - coords[2], 2);
29580 var y = Math.pow(coords[1] - coords[3], 2);
29582 this.startDistance = Math.sqrt(x + y);
29584 this.startScale = this.scale;
29586 this.pinching = true;
29587 this.dragable = false;
29591 onTouchMove : function(e)
29593 if(!this.pinching && !this.dragable){
29597 var touches = e.browserEvent.touches;
29604 this.onMouseMove(e);
29610 for(var i = 0, finger; finger = touches[i]; i++){
29611 coords.push(finger.pageX, finger.pageY);
29614 var x = Math.pow(coords[0] - coords[2], 2);
29615 var y = Math.pow(coords[1] - coords[3], 2);
29617 this.endDistance = Math.sqrt(x + y);
29619 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
29621 if(!this.zoomable()){
29622 this.scale = this.startScale;
29630 onTouchEnd : function(e)
29632 this.pinching = false;
29633 this.dragable = false;
29637 process : function(file, crop)
29640 this.maskEl.mask(this.loadingText);
29643 this.xhr = new XMLHttpRequest();
29645 file.xhr = this.xhr;
29647 this.xhr.open(this.method, this.url, true);
29650 "Accept": "application/json",
29651 "Cache-Control": "no-cache",
29652 "X-Requested-With": "XMLHttpRequest"
29655 for (var headerName in headers) {
29656 var headerValue = headers[headerName];
29658 this.xhr.setRequestHeader(headerName, headerValue);
29664 this.xhr.onload = function()
29666 _this.xhrOnLoad(_this.xhr);
29669 this.xhr.onerror = function()
29671 _this.xhrOnError(_this.xhr);
29674 var formData = new FormData();
29676 formData.append('returnHTML', 'NO');
29679 formData.append('crop', crop);
29682 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
29683 formData.append(this.paramName, file, file.name);
29686 if(typeof(file.filename) != 'undefined'){
29687 formData.append('filename', file.filename);
29690 if(typeof(file.mimetype) != 'undefined'){
29691 formData.append('mimetype', file.mimetype);
29694 if(this.fireEvent('arrange', this, formData) != false){
29695 this.xhr.send(formData);
29699 xhrOnLoad : function(xhr)
29702 this.maskEl.unmask();
29705 if (xhr.readyState !== 4) {
29706 this.fireEvent('exception', this, xhr);
29710 var response = Roo.decode(xhr.responseText);
29712 if(!response.success){
29713 this.fireEvent('exception', this, xhr);
29717 var response = Roo.decode(xhr.responseText);
29719 this.fireEvent('upload', this, response);
29723 xhrOnError : function()
29726 this.maskEl.unmask();
29729 Roo.log('xhr on error');
29731 var response = Roo.decode(xhr.responseText);
29737 prepare : function(file)
29740 this.maskEl.mask(this.loadingText);
29746 if(typeof(file) === 'string'){
29747 this.loadCanvas(file);
29751 if(!file || !this.urlAPI){
29756 this.cropType = file.type;
29760 if(this.fireEvent('prepare', this, this.file) != false){
29762 var reader = new FileReader();
29764 reader.onload = function (e) {
29765 if (e.target.error) {
29766 Roo.log(e.target.error);
29770 var buffer = e.target.result,
29771 dataView = new DataView(buffer),
29773 maxOffset = dataView.byteLength - 4,
29777 if (dataView.getUint16(0) === 0xffd8) {
29778 while (offset < maxOffset) {
29779 markerBytes = dataView.getUint16(offset);
29781 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
29782 markerLength = dataView.getUint16(offset + 2) + 2;
29783 if (offset + markerLength > dataView.byteLength) {
29784 Roo.log('Invalid meta data: Invalid segment size.');
29788 if(markerBytes == 0xffe1){
29789 _this.parseExifData(
29796 offset += markerLength;
29806 var url = _this.urlAPI.createObjectURL(_this.file);
29808 _this.loadCanvas(url);
29813 reader.readAsArrayBuffer(this.file);
29819 parseExifData : function(dataView, offset, length)
29821 var tiffOffset = offset + 10,
29825 if (dataView.getUint32(offset + 4) !== 0x45786966) {
29826 // No Exif data, might be XMP data instead
29830 // Check for the ASCII code for "Exif" (0x45786966):
29831 if (dataView.getUint32(offset + 4) !== 0x45786966) {
29832 // No Exif data, might be XMP data instead
29835 if (tiffOffset + 8 > dataView.byteLength) {
29836 Roo.log('Invalid Exif data: Invalid segment size.');
29839 // Check for the two null bytes:
29840 if (dataView.getUint16(offset + 8) !== 0x0000) {
29841 Roo.log('Invalid Exif data: Missing byte alignment offset.');
29844 // Check the byte alignment:
29845 switch (dataView.getUint16(tiffOffset)) {
29847 littleEndian = true;
29850 littleEndian = false;
29853 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
29856 // Check for the TIFF tag marker (0x002A):
29857 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
29858 Roo.log('Invalid Exif data: Missing TIFF marker.');
29861 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
29862 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
29864 this.parseExifTags(
29867 tiffOffset + dirOffset,
29872 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
29877 if (dirOffset + 6 > dataView.byteLength) {
29878 Roo.log('Invalid Exif data: Invalid directory offset.');
29881 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
29882 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
29883 if (dirEndOffset + 4 > dataView.byteLength) {
29884 Roo.log('Invalid Exif data: Invalid directory size.');
29887 for (i = 0; i < tagsNumber; i += 1) {
29891 dirOffset + 2 + 12 * i, // tag offset
29895 // Return the offset to the next directory:
29896 return dataView.getUint32(dirEndOffset, littleEndian);
29899 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
29901 var tag = dataView.getUint16(offset, littleEndian);
29903 this.exif[tag] = this.getExifValue(
29907 dataView.getUint16(offset + 2, littleEndian), // tag type
29908 dataView.getUint32(offset + 4, littleEndian), // tag length
29913 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
29915 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
29924 Roo.log('Invalid Exif data: Invalid tag type.');
29928 tagSize = tagType.size * length;
29929 // Determine if the value is contained in the dataOffset bytes,
29930 // or if the value at the dataOffset is a pointer to the actual data:
29931 dataOffset = tagSize > 4 ?
29932 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
29933 if (dataOffset + tagSize > dataView.byteLength) {
29934 Roo.log('Invalid Exif data: Invalid data offset.');
29937 if (length === 1) {
29938 return tagType.getValue(dataView, dataOffset, littleEndian);
29941 for (i = 0; i < length; i += 1) {
29942 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
29945 if (tagType.ascii) {
29947 // Concatenate the chars:
29948 for (i = 0; i < values.length; i += 1) {
29950 // Ignore the terminating NULL byte(s):
29951 if (c === '\u0000') {
29963 Roo.apply(Roo.bootstrap.UploadCropbox, {
29965 'Orientation': 0x0112
29969 1: 0, //'top-left',
29971 3: 180, //'bottom-right',
29972 // 4: 'bottom-left',
29974 6: 90, //'right-top',
29975 // 7: 'right-bottom',
29976 8: 270 //'left-bottom'
29980 // byte, 8-bit unsigned int:
29982 getValue: function (dataView, dataOffset) {
29983 return dataView.getUint8(dataOffset);
29987 // ascii, 8-bit byte:
29989 getValue: function (dataView, dataOffset) {
29990 return String.fromCharCode(dataView.getUint8(dataOffset));
29995 // short, 16 bit int:
29997 getValue: function (dataView, dataOffset, littleEndian) {
29998 return dataView.getUint16(dataOffset, littleEndian);
30002 // long, 32 bit int:
30004 getValue: function (dataView, dataOffset, littleEndian) {
30005 return dataView.getUint32(dataOffset, littleEndian);
30009 // rational = two long values, first is numerator, second is denominator:
30011 getValue: function (dataView, dataOffset, littleEndian) {
30012 return dataView.getUint32(dataOffset, littleEndian) /
30013 dataView.getUint32(dataOffset + 4, littleEndian);
30017 // slong, 32 bit signed int:
30019 getValue: function (dataView, dataOffset, littleEndian) {
30020 return dataView.getInt32(dataOffset, littleEndian);
30024 // srational, two slongs, first is numerator, second is denominator:
30026 getValue: function (dataView, dataOffset, littleEndian) {
30027 return dataView.getInt32(dataOffset, littleEndian) /
30028 dataView.getInt32(dataOffset + 4, littleEndian);
30038 cls : 'btn-group roo-upload-cropbox-rotate-left',
30039 action : 'rotate-left',
30043 cls : 'btn btn-default',
30044 html : '<i class="fa fa-undo"></i>'
30050 cls : 'btn-group roo-upload-cropbox-picture',
30051 action : 'picture',
30055 cls : 'btn btn-default',
30056 html : '<i class="fa fa-picture-o"></i>'
30062 cls : 'btn-group roo-upload-cropbox-rotate-right',
30063 action : 'rotate-right',
30067 cls : 'btn btn-default',
30068 html : '<i class="fa fa-repeat"></i>'
30076 cls : 'btn-group roo-upload-cropbox-rotate-left',
30077 action : 'rotate-left',
30081 cls : 'btn btn-default',
30082 html : '<i class="fa fa-undo"></i>'
30088 cls : 'btn-group roo-upload-cropbox-download',
30089 action : 'download',
30093 cls : 'btn btn-default',
30094 html : '<i class="fa fa-download"></i>'
30100 cls : 'btn-group roo-upload-cropbox-crop',
30105 cls : 'btn btn-default',
30106 html : '<i class="fa fa-crop"></i>'
30112 cls : 'btn-group roo-upload-cropbox-trash',
30117 cls : 'btn btn-default',
30118 html : '<i class="fa fa-trash"></i>'
30124 cls : 'btn-group roo-upload-cropbox-rotate-right',
30125 action : 'rotate-right',
30129 cls : 'btn btn-default',
30130 html : '<i class="fa fa-repeat"></i>'
30138 cls : 'btn-group roo-upload-cropbox-rotate-left',
30139 action : 'rotate-left',
30143 cls : 'btn btn-default',
30144 html : '<i class="fa fa-undo"></i>'
30150 cls : 'btn-group roo-upload-cropbox-rotate-right',
30151 action : 'rotate-right',
30155 cls : 'btn btn-default',
30156 html : '<i class="fa fa-repeat"></i>'
30169 * @class Roo.bootstrap.DocumentManager
30170 * @extends Roo.bootstrap.Component
30171 * Bootstrap DocumentManager class
30172 * @cfg {String} paramName default 'imageUpload'
30173 * @cfg {String} toolTipName default 'filename'
30174 * @cfg {String} method default POST
30175 * @cfg {String} url action url
30176 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
30177 * @cfg {Boolean} multiple multiple upload default true
30178 * @cfg {Number} thumbSize default 300
30179 * @cfg {String} fieldLabel
30180 * @cfg {Number} labelWidth default 4
30181 * @cfg {String} labelAlign (left|top) default left
30182 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
30183 * @cfg {Number} labellg set the width of label (1-12)
30184 * @cfg {Number} labelmd set the width of label (1-12)
30185 * @cfg {Number} labelsm set the width of label (1-12)
30186 * @cfg {Number} labelxs set the width of label (1-12)
30189 * Create a new DocumentManager
30190 * @param {Object} config The config object
30193 Roo.bootstrap.DocumentManager = function(config){
30194 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
30197 this.delegates = [];
30202 * Fire when initial the DocumentManager
30203 * @param {Roo.bootstrap.DocumentManager} this
30208 * inspect selected file
30209 * @param {Roo.bootstrap.DocumentManager} this
30210 * @param {File} file
30215 * Fire when xhr load exception
30216 * @param {Roo.bootstrap.DocumentManager} this
30217 * @param {XMLHttpRequest} xhr
30219 "exception" : true,
30221 * @event afterupload
30222 * Fire when xhr load exception
30223 * @param {Roo.bootstrap.DocumentManager} this
30224 * @param {XMLHttpRequest} xhr
30226 "afterupload" : true,
30229 * prepare the form data
30230 * @param {Roo.bootstrap.DocumentManager} this
30231 * @param {Object} formData
30236 * Fire when remove the file
30237 * @param {Roo.bootstrap.DocumentManager} this
30238 * @param {Object} file
30243 * Fire after refresh the file
30244 * @param {Roo.bootstrap.DocumentManager} this
30249 * Fire after click the image
30250 * @param {Roo.bootstrap.DocumentManager} this
30251 * @param {Object} file
30256 * Fire when upload a image and editable set to true
30257 * @param {Roo.bootstrap.DocumentManager} this
30258 * @param {Object} file
30262 * @event beforeselectfile
30263 * Fire before select file
30264 * @param {Roo.bootstrap.DocumentManager} this
30266 "beforeselectfile" : true,
30269 * Fire before process file
30270 * @param {Roo.bootstrap.DocumentManager} this
30271 * @param {Object} file
30275 * @event previewrendered
30276 * Fire when preview rendered
30277 * @param {Roo.bootstrap.DocumentManager} this
30278 * @param {Object} file
30280 "previewrendered" : true,
30283 "previewResize" : true
30288 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
30297 paramName : 'imageUpload',
30298 toolTipName : 'filename',
30301 labelAlign : 'left',
30311 getAutoCreate : function()
30313 var managerWidget = {
30315 cls : 'roo-document-manager',
30319 cls : 'roo-document-manager-selector',
30324 cls : 'roo-document-manager-uploader',
30328 cls : 'roo-document-manager-upload-btn',
30329 html : '<i class="fa fa-plus"></i>'
30340 cls : 'column col-md-12',
30345 if(this.fieldLabel.length){
30350 cls : 'column col-md-12',
30351 html : this.fieldLabel
30355 cls : 'column col-md-12',
30360 if(this.labelAlign == 'left'){
30365 html : this.fieldLabel
30374 if(this.labelWidth > 12){
30375 content[0].style = "width: " + this.labelWidth + 'px';
30378 if(this.labelWidth < 13 && this.labelmd == 0){
30379 this.labelmd = this.labelWidth;
30382 if(this.labellg > 0){
30383 content[0].cls += ' col-lg-' + this.labellg;
30384 content[1].cls += ' col-lg-' + (12 - this.labellg);
30387 if(this.labelmd > 0){
30388 content[0].cls += ' col-md-' + this.labelmd;
30389 content[1].cls += ' col-md-' + (12 - this.labelmd);
30392 if(this.labelsm > 0){
30393 content[0].cls += ' col-sm-' + this.labelsm;
30394 content[1].cls += ' col-sm-' + (12 - this.labelsm);
30397 if(this.labelxs > 0){
30398 content[0].cls += ' col-xs-' + this.labelxs;
30399 content[1].cls += ' col-xs-' + (12 - this.labelxs);
30407 cls : 'row clearfix',
30415 initEvents : function()
30417 this.managerEl = this.el.select('.roo-document-manager', true).first();
30418 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30420 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
30421 this.selectorEl.hide();
30424 this.selectorEl.attr('multiple', 'multiple');
30427 this.selectorEl.on('change', this.onFileSelected, this);
30429 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
30430 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30432 this.uploader.on('click', this.onUploaderClick, this);
30434 this.renderProgressDialog();
30438 window.addEventListener("resize", function() { _this.refresh(); } );
30440 this.fireEvent('initial', this);
30443 renderProgressDialog : function()
30447 this.progressDialog = new Roo.bootstrap.Modal({
30448 cls : 'roo-document-manager-progress-dialog',
30449 allow_close : false,
30460 btnclick : function() {
30461 _this.uploadCancel();
30467 this.progressDialog.render(Roo.get(document.body));
30469 this.progress = new Roo.bootstrap.Progress({
30470 cls : 'roo-document-manager-progress',
30475 this.progress.render(this.progressDialog.getChildContainer());
30477 this.progressBar = new Roo.bootstrap.ProgressBar({
30478 cls : 'roo-document-manager-progress-bar',
30481 aria_valuemax : 12,
30485 this.progressBar.render(this.progress.getChildContainer());
30488 onUploaderClick : function(e)
30490 e.preventDefault();
30492 if(this.fireEvent('beforeselectfile', this) != false){
30493 this.selectorEl.dom.click();
30498 onFileSelected : function(e)
30500 e.preventDefault();
30502 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
30506 Roo.each(this.selectorEl.dom.files, function(file){
30507 if(this.fireEvent('inspect', this, file) != false){
30508 this.files.push(file);
30518 this.selectorEl.dom.value = '';
30520 if(!this.files || !this.files.length){
30524 if(this.boxes > 0 && this.files.length > this.boxes){
30525 this.files = this.files.slice(0, this.boxes);
30528 this.uploader.show();
30530 if(this.boxes > 0 && this.files.length > this.boxes - 1){
30531 this.uploader.hide();
30540 Roo.each(this.files, function(file){
30542 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
30543 var f = this.renderPreview(file);
30548 if(file.type.indexOf('image') != -1){
30549 this.delegates.push(
30551 _this.process(file);
30552 }).createDelegate(this)
30560 _this.process(file);
30561 }).createDelegate(this)
30566 this.files = files;
30568 this.delegates = this.delegates.concat(docs);
30570 if(!this.delegates.length){
30575 this.progressBar.aria_valuemax = this.delegates.length;
30582 arrange : function()
30584 if(!this.delegates.length){
30585 this.progressDialog.hide();
30590 var delegate = this.delegates.shift();
30592 this.progressDialog.show();
30594 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
30596 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
30601 refresh : function()
30603 this.uploader.show();
30605 if(this.boxes > 0 && this.files.length > this.boxes - 1){
30606 this.uploader.hide();
30609 Roo.isTouch ? this.closable(false) : this.closable(true);
30611 this.fireEvent('refresh', this);
30614 onRemove : function(e, el, o)
30616 e.preventDefault();
30618 this.fireEvent('remove', this, o);
30622 remove : function(o)
30626 Roo.each(this.files, function(file){
30627 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
30636 this.files = files;
30643 Roo.each(this.files, function(file){
30648 file.target.remove();
30657 onClick : function(e, el, o)
30659 e.preventDefault();
30661 this.fireEvent('click', this, o);
30665 closable : function(closable)
30667 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
30669 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
30681 xhrOnLoad : function(xhr)
30683 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
30687 if (xhr.readyState !== 4) {
30689 this.fireEvent('exception', this, xhr);
30693 var response = Roo.decode(xhr.responseText);
30695 if(!response.success){
30697 this.fireEvent('exception', this, xhr);
30701 var file = this.renderPreview(response.data);
30703 this.files.push(file);
30707 this.fireEvent('afterupload', this, xhr);
30711 xhrOnError : function(xhr)
30713 Roo.log('xhr on error');
30715 var response = Roo.decode(xhr.responseText);
30722 process : function(file)
30724 if(this.fireEvent('process', this, file) !== false){
30725 if(this.editable && file.type.indexOf('image') != -1){
30726 this.fireEvent('edit', this, file);
30730 this.uploadStart(file, false);
30737 uploadStart : function(file, crop)
30739 this.xhr = new XMLHttpRequest();
30741 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
30746 file.xhr = this.xhr;
30748 this.managerEl.createChild({
30750 cls : 'roo-document-manager-loading',
30754 tooltip : file.name,
30755 cls : 'roo-document-manager-thumb',
30756 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
30762 this.xhr.open(this.method, this.url, true);
30765 "Accept": "application/json",
30766 "Cache-Control": "no-cache",
30767 "X-Requested-With": "XMLHttpRequest"
30770 for (var headerName in headers) {
30771 var headerValue = headers[headerName];
30773 this.xhr.setRequestHeader(headerName, headerValue);
30779 this.xhr.onload = function()
30781 _this.xhrOnLoad(_this.xhr);
30784 this.xhr.onerror = function()
30786 _this.xhrOnError(_this.xhr);
30789 var formData = new FormData();
30791 formData.append('returnHTML', 'NO');
30794 formData.append('crop', crop);
30797 formData.append(this.paramName, file, file.name);
30804 if(this.fireEvent('prepare', this, formData, options) != false){
30806 if(options.manually){
30810 this.xhr.send(formData);
30814 this.uploadCancel();
30817 uploadCancel : function()
30823 this.delegates = [];
30825 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
30832 renderPreview : function(file)
30834 if(typeof(file.target) != 'undefined' && file.target){
30838 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
30840 var previewEl = this.managerEl.createChild({
30842 cls : 'roo-document-manager-preview',
30846 tooltip : file[this.toolTipName],
30847 cls : 'roo-document-manager-thumb',
30848 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
30853 html : '<i class="fa fa-times-circle"></i>'
30858 var close = previewEl.select('button.close', true).first();
30860 close.on('click', this.onRemove, this, file);
30862 file.target = previewEl;
30864 var image = previewEl.select('img', true).first();
30868 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
30870 image.on('click', this.onClick, this, file);
30872 this.fireEvent('previewrendered', this, file);
30878 onPreviewLoad : function(file, image)
30880 if(typeof(file.target) == 'undefined' || !file.target){
30884 var width = image.dom.naturalWidth || image.dom.width;
30885 var height = image.dom.naturalHeight || image.dom.height;
30887 if(!this.previewResize) {
30891 if(width > height){
30892 file.target.addClass('wide');
30896 file.target.addClass('tall');
30901 uploadFromSource : function(file, crop)
30903 this.xhr = new XMLHttpRequest();
30905 this.managerEl.createChild({
30907 cls : 'roo-document-manager-loading',
30911 tooltip : file.name,
30912 cls : 'roo-document-manager-thumb',
30913 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
30919 this.xhr.open(this.method, this.url, true);
30922 "Accept": "application/json",
30923 "Cache-Control": "no-cache",
30924 "X-Requested-With": "XMLHttpRequest"
30927 for (var headerName in headers) {
30928 var headerValue = headers[headerName];
30930 this.xhr.setRequestHeader(headerName, headerValue);
30936 this.xhr.onload = function()
30938 _this.xhrOnLoad(_this.xhr);
30941 this.xhr.onerror = function()
30943 _this.xhrOnError(_this.xhr);
30946 var formData = new FormData();
30948 formData.append('returnHTML', 'NO');
30950 formData.append('crop', crop);
30952 if(typeof(file.filename) != 'undefined'){
30953 formData.append('filename', file.filename);
30956 if(typeof(file.mimetype) != 'undefined'){
30957 formData.append('mimetype', file.mimetype);
30962 if(this.fireEvent('prepare', this, formData) != false){
30963 this.xhr.send(formData);
30973 * @class Roo.bootstrap.DocumentViewer
30974 * @extends Roo.bootstrap.Component
30975 * Bootstrap DocumentViewer class
30976 * @cfg {Boolean} showDownload (true|false) show download button (default true)
30977 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
30980 * Create a new DocumentViewer
30981 * @param {Object} config The config object
30984 Roo.bootstrap.DocumentViewer = function(config){
30985 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
30990 * Fire after initEvent
30991 * @param {Roo.bootstrap.DocumentViewer} this
30997 * @param {Roo.bootstrap.DocumentViewer} this
31002 * Fire after download button
31003 * @param {Roo.bootstrap.DocumentViewer} this
31008 * Fire after trash button
31009 * @param {Roo.bootstrap.DocumentViewer} this
31016 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
31018 showDownload : true,
31022 getAutoCreate : function()
31026 cls : 'roo-document-viewer',
31030 cls : 'roo-document-viewer-body',
31034 cls : 'roo-document-viewer-thumb',
31038 cls : 'roo-document-viewer-image'
31046 cls : 'roo-document-viewer-footer',
31049 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
31053 cls : 'btn-group roo-document-viewer-download',
31057 cls : 'btn btn-default',
31058 html : '<i class="fa fa-download"></i>'
31064 cls : 'btn-group roo-document-viewer-trash',
31068 cls : 'btn btn-default',
31069 html : '<i class="fa fa-trash"></i>'
31082 initEvents : function()
31084 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
31085 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
31087 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
31088 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
31090 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
31091 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
31093 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
31094 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
31096 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
31097 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
31099 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
31100 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
31102 this.bodyEl.on('click', this.onClick, this);
31103 this.downloadBtn.on('click', this.onDownload, this);
31104 this.trashBtn.on('click', this.onTrash, this);
31106 this.downloadBtn.hide();
31107 this.trashBtn.hide();
31109 if(this.showDownload){
31110 this.downloadBtn.show();
31113 if(this.showTrash){
31114 this.trashBtn.show();
31117 if(!this.showDownload && !this.showTrash) {
31118 this.footerEl.hide();
31123 initial : function()
31125 this.fireEvent('initial', this);
31129 onClick : function(e)
31131 e.preventDefault();
31133 this.fireEvent('click', this);
31136 onDownload : function(e)
31138 e.preventDefault();
31140 this.fireEvent('download', this);
31143 onTrash : function(e)
31145 e.preventDefault();
31147 this.fireEvent('trash', this);
31159 * @class Roo.bootstrap.NavProgressBar
31160 * @extends Roo.bootstrap.Component
31161 * Bootstrap NavProgressBar class
31164 * Create a new nav progress bar
31165 * @param {Object} config The config object
31168 Roo.bootstrap.NavProgressBar = function(config){
31169 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
31171 this.bullets = this.bullets || [];
31173 // Roo.bootstrap.NavProgressBar.register(this);
31177 * Fires when the active item changes
31178 * @param {Roo.bootstrap.NavProgressBar} this
31179 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
31180 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
31187 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
31192 getAutoCreate : function()
31194 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
31198 cls : 'roo-navigation-bar-group',
31202 cls : 'roo-navigation-top-bar'
31206 cls : 'roo-navigation-bullets-bar',
31210 cls : 'roo-navigation-bar'
31217 cls : 'roo-navigation-bottom-bar'
31227 initEvents: function()
31232 onRender : function(ct, position)
31234 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
31236 if(this.bullets.length){
31237 Roo.each(this.bullets, function(b){
31246 addItem : function(cfg)
31248 var item = new Roo.bootstrap.NavProgressItem(cfg);
31250 item.parentId = this.id;
31251 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
31254 var top = new Roo.bootstrap.Element({
31256 cls : 'roo-navigation-bar-text'
31259 var bottom = new Roo.bootstrap.Element({
31261 cls : 'roo-navigation-bar-text'
31264 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
31265 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
31267 var topText = new Roo.bootstrap.Element({
31269 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
31272 var bottomText = new Roo.bootstrap.Element({
31274 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
31277 topText.onRender(top.el, null);
31278 bottomText.onRender(bottom.el, null);
31281 item.bottomEl = bottom;
31284 this.barItems.push(item);
31289 getActive : function()
31291 var active = false;
31293 Roo.each(this.barItems, function(v){
31295 if (!v.isActive()) {
31307 setActiveItem : function(item)
31311 Roo.each(this.barItems, function(v){
31312 if (v.rid == item.rid) {
31316 if (v.isActive()) {
31317 v.setActive(false);
31322 item.setActive(true);
31324 this.fireEvent('changed', this, item, prev);
31327 getBarItem: function(rid)
31331 Roo.each(this.barItems, function(e) {
31332 if (e.rid != rid) {
31343 indexOfItem : function(item)
31347 Roo.each(this.barItems, function(v, i){
31349 if (v.rid != item.rid) {
31360 setActiveNext : function()
31362 var i = this.indexOfItem(this.getActive());
31364 if (i > this.barItems.length) {
31368 this.setActiveItem(this.barItems[i+1]);
31371 setActivePrev : function()
31373 var i = this.indexOfItem(this.getActive());
31379 this.setActiveItem(this.barItems[i-1]);
31382 format : function()
31384 if(!this.barItems.length){
31388 var width = 100 / this.barItems.length;
31390 Roo.each(this.barItems, function(i){
31391 i.el.setStyle('width', width + '%');
31392 i.topEl.el.setStyle('width', width + '%');
31393 i.bottomEl.el.setStyle('width', width + '%');
31402 * Nav Progress Item
31407 * @class Roo.bootstrap.NavProgressItem
31408 * @extends Roo.bootstrap.Component
31409 * Bootstrap NavProgressItem class
31410 * @cfg {String} rid the reference id
31411 * @cfg {Boolean} active (true|false) Is item active default false
31412 * @cfg {Boolean} disabled (true|false) Is item active default false
31413 * @cfg {String} html
31414 * @cfg {String} position (top|bottom) text position default bottom
31415 * @cfg {String} icon show icon instead of number
31418 * Create a new NavProgressItem
31419 * @param {Object} config The config object
31421 Roo.bootstrap.NavProgressItem = function(config){
31422 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
31427 * The raw click event for the entire grid.
31428 * @param {Roo.bootstrap.NavProgressItem} this
31429 * @param {Roo.EventObject} e
31436 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
31442 position : 'bottom',
31445 getAutoCreate : function()
31447 var iconCls = 'roo-navigation-bar-item-icon';
31449 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
31453 cls: 'roo-navigation-bar-item',
31463 cfg.cls += ' active';
31466 cfg.cls += ' disabled';
31472 disable : function()
31474 this.setDisabled(true);
31477 enable : function()
31479 this.setDisabled(false);
31482 initEvents: function()
31484 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
31486 this.iconEl.on('click', this.onClick, this);
31489 onClick : function(e)
31491 e.preventDefault();
31497 if(this.fireEvent('click', this, e) === false){
31501 this.parent().setActiveItem(this);
31504 isActive: function ()
31506 return this.active;
31509 setActive : function(state)
31511 if(this.active == state){
31515 this.active = state;
31518 this.el.addClass('active');
31522 this.el.removeClass('active');
31527 setDisabled : function(state)
31529 if(this.disabled == state){
31533 this.disabled = state;
31536 this.el.addClass('disabled');
31540 this.el.removeClass('disabled');
31543 tooltipEl : function()
31545 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
31558 * @class Roo.bootstrap.FieldLabel
31559 * @extends Roo.bootstrap.Component
31560 * Bootstrap FieldLabel class
31561 * @cfg {String} html contents of the element
31562 * @cfg {String} tag tag of the element default label
31563 * @cfg {String} cls class of the element
31564 * @cfg {String} target label target
31565 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
31566 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
31567 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
31568 * @cfg {String} iconTooltip default "This field is required"
31569 * @cfg {String} indicatorpos (left|right) default left
31572 * Create a new FieldLabel
31573 * @param {Object} config The config object
31576 Roo.bootstrap.FieldLabel = function(config){
31577 Roo.bootstrap.Element.superclass.constructor.call(this, config);
31582 * Fires after the field has been marked as invalid.
31583 * @param {Roo.form.FieldLabel} this
31584 * @param {String} msg The validation message
31589 * Fires after the field has been validated with no errors.
31590 * @param {Roo.form.FieldLabel} this
31596 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
31603 invalidClass : 'has-warning',
31604 validClass : 'has-success',
31605 iconTooltip : 'This field is required',
31606 indicatorpos : 'left',
31608 getAutoCreate : function(){
31611 if (!this.allowBlank) {
31617 cls : 'roo-bootstrap-field-label ' + this.cls,
31622 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
31623 tooltip : this.iconTooltip
31632 if(this.indicatorpos == 'right'){
31635 cls : 'roo-bootstrap-field-label ' + this.cls,
31644 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
31645 tooltip : this.iconTooltip
31654 initEvents: function()
31656 Roo.bootstrap.Element.superclass.initEvents.call(this);
31658 this.indicator = this.indicatorEl();
31660 if(this.indicator){
31661 this.indicator.removeClass('visible');
31662 this.indicator.addClass('invisible');
31665 Roo.bootstrap.FieldLabel.register(this);
31668 indicatorEl : function()
31670 var indicator = this.el.select('i.roo-required-indicator',true).first();
31681 * Mark this field as valid
31683 markValid : function()
31685 if(this.indicator){
31686 this.indicator.removeClass('visible');
31687 this.indicator.addClass('invisible');
31689 if (Roo.bootstrap.version == 3) {
31690 this.el.removeClass(this.invalidClass);
31691 this.el.addClass(this.validClass);
31693 this.el.removeClass('is-invalid');
31694 this.el.addClass('is-valid');
31698 this.fireEvent('valid', this);
31702 * Mark this field as invalid
31703 * @param {String} msg The validation message
31705 markInvalid : function(msg)
31707 if(this.indicator){
31708 this.indicator.removeClass('invisible');
31709 this.indicator.addClass('visible');
31711 if (Roo.bootstrap.version == 3) {
31712 this.el.removeClass(this.validClass);
31713 this.el.addClass(this.invalidClass);
31715 this.el.removeClass('is-valid');
31716 this.el.addClass('is-invalid');
31720 this.fireEvent('invalid', this, msg);
31726 Roo.apply(Roo.bootstrap.FieldLabel, {
31731 * register a FieldLabel Group
31732 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
31734 register : function(label)
31736 if(this.groups.hasOwnProperty(label.target)){
31740 this.groups[label.target] = label;
31744 * fetch a FieldLabel Group based on the target
31745 * @param {string} target
31746 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
31748 get: function(target) {
31749 if (typeof(this.groups[target]) == 'undefined') {
31753 return this.groups[target] ;
31762 * page DateSplitField.
31768 * @class Roo.bootstrap.DateSplitField
31769 * @extends Roo.bootstrap.Component
31770 * Bootstrap DateSplitField class
31771 * @cfg {string} fieldLabel - the label associated
31772 * @cfg {Number} labelWidth set the width of label (0-12)
31773 * @cfg {String} labelAlign (top|left)
31774 * @cfg {Boolean} dayAllowBlank (true|false) default false
31775 * @cfg {Boolean} monthAllowBlank (true|false) default false
31776 * @cfg {Boolean} yearAllowBlank (true|false) default false
31777 * @cfg {string} dayPlaceholder
31778 * @cfg {string} monthPlaceholder
31779 * @cfg {string} yearPlaceholder
31780 * @cfg {string} dayFormat default 'd'
31781 * @cfg {string} monthFormat default 'm'
31782 * @cfg {string} yearFormat default 'Y'
31783 * @cfg {Number} labellg set the width of label (1-12)
31784 * @cfg {Number} labelmd set the width of label (1-12)
31785 * @cfg {Number} labelsm set the width of label (1-12)
31786 * @cfg {Number} labelxs set the width of label (1-12)
31790 * Create a new DateSplitField
31791 * @param {Object} config The config object
31794 Roo.bootstrap.DateSplitField = function(config){
31795 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
31801 * getting the data of years
31802 * @param {Roo.bootstrap.DateSplitField} this
31803 * @param {Object} years
31808 * getting the data of days
31809 * @param {Roo.bootstrap.DateSplitField} this
31810 * @param {Object} days
31815 * Fires after the field has been marked as invalid.
31816 * @param {Roo.form.Field} this
31817 * @param {String} msg The validation message
31822 * Fires after the field has been validated with no errors.
31823 * @param {Roo.form.Field} this
31829 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
31832 labelAlign : 'top',
31834 dayAllowBlank : false,
31835 monthAllowBlank : false,
31836 yearAllowBlank : false,
31837 dayPlaceholder : '',
31838 monthPlaceholder : '',
31839 yearPlaceholder : '',
31843 isFormField : true,
31849 getAutoCreate : function()
31853 cls : 'row roo-date-split-field-group',
31858 cls : 'form-hidden-field roo-date-split-field-group-value',
31864 var labelCls = 'col-md-12';
31865 var contentCls = 'col-md-4';
31867 if(this.fieldLabel){
31871 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
31875 html : this.fieldLabel
31880 if(this.labelAlign == 'left'){
31882 if(this.labelWidth > 12){
31883 label.style = "width: " + this.labelWidth + 'px';
31886 if(this.labelWidth < 13 && this.labelmd == 0){
31887 this.labelmd = this.labelWidth;
31890 if(this.labellg > 0){
31891 labelCls = ' col-lg-' + this.labellg;
31892 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
31895 if(this.labelmd > 0){
31896 labelCls = ' col-md-' + this.labelmd;
31897 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
31900 if(this.labelsm > 0){
31901 labelCls = ' col-sm-' + this.labelsm;
31902 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
31905 if(this.labelxs > 0){
31906 labelCls = ' col-xs-' + this.labelxs;
31907 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
31911 label.cls += ' ' + labelCls;
31913 cfg.cn.push(label);
31916 Roo.each(['day', 'month', 'year'], function(t){
31919 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
31926 inputEl: function ()
31928 return this.el.select('.roo-date-split-field-group-value', true).first();
31931 onRender : function(ct, position)
31935 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
31937 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
31939 this.dayField = new Roo.bootstrap.ComboBox({
31940 allowBlank : this.dayAllowBlank,
31941 alwaysQuery : true,
31942 displayField : 'value',
31945 forceSelection : true,
31947 placeholder : this.dayPlaceholder,
31948 selectOnFocus : true,
31949 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
31950 triggerAction : 'all',
31952 valueField : 'value',
31953 store : new Roo.data.SimpleStore({
31954 data : (function() {
31956 _this.fireEvent('days', _this, days);
31959 fields : [ 'value' ]
31962 select : function (_self, record, index)
31964 _this.setValue(_this.getValue());
31969 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
31971 this.monthField = new Roo.bootstrap.MonthField({
31972 after : '<i class=\"fa fa-calendar\"></i>',
31973 allowBlank : this.monthAllowBlank,
31974 placeholder : this.monthPlaceholder,
31977 render : function (_self)
31979 this.el.select('span.input-group-addon', true).first().on('click', function(e){
31980 e.preventDefault();
31984 select : function (_self, oldvalue, newvalue)
31986 _this.setValue(_this.getValue());
31991 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
31993 this.yearField = new Roo.bootstrap.ComboBox({
31994 allowBlank : this.yearAllowBlank,
31995 alwaysQuery : true,
31996 displayField : 'value',
31999 forceSelection : true,
32001 placeholder : this.yearPlaceholder,
32002 selectOnFocus : true,
32003 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32004 triggerAction : 'all',
32006 valueField : 'value',
32007 store : new Roo.data.SimpleStore({
32008 data : (function() {
32010 _this.fireEvent('years', _this, years);
32013 fields : [ 'value' ]
32016 select : function (_self, record, index)
32018 _this.setValue(_this.getValue());
32023 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
32026 setValue : function(v, format)
32028 this.inputEl.dom.value = v;
32030 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
32032 var d = Date.parseDate(v, f);
32039 this.setDay(d.format(this.dayFormat));
32040 this.setMonth(d.format(this.monthFormat));
32041 this.setYear(d.format(this.yearFormat));
32048 setDay : function(v)
32050 this.dayField.setValue(v);
32051 this.inputEl.dom.value = this.getValue();
32056 setMonth : function(v)
32058 this.monthField.setValue(v, true);
32059 this.inputEl.dom.value = this.getValue();
32064 setYear : function(v)
32066 this.yearField.setValue(v);
32067 this.inputEl.dom.value = this.getValue();
32072 getDay : function()
32074 return this.dayField.getValue();
32077 getMonth : function()
32079 return this.monthField.getValue();
32082 getYear : function()
32084 return this.yearField.getValue();
32087 getValue : function()
32089 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
32091 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
32101 this.inputEl.dom.value = '';
32106 validate : function()
32108 var d = this.dayField.validate();
32109 var m = this.monthField.validate();
32110 var y = this.yearField.validate();
32115 (!this.dayAllowBlank && !d) ||
32116 (!this.monthAllowBlank && !m) ||
32117 (!this.yearAllowBlank && !y)
32122 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
32131 this.markInvalid();
32136 markValid : function()
32139 var label = this.el.select('label', true).first();
32140 var icon = this.el.select('i.fa-star', true).first();
32146 this.fireEvent('valid', this);
32150 * Mark this field as invalid
32151 * @param {String} msg The validation message
32153 markInvalid : function(msg)
32156 var label = this.el.select('label', true).first();
32157 var icon = this.el.select('i.fa-star', true).first();
32159 if(label && !icon){
32160 this.el.select('.roo-date-split-field-label', true).createChild({
32162 cls : 'text-danger fa fa-lg fa-star',
32163 tooltip : 'This field is required',
32164 style : 'margin-right:5px;'
32168 this.fireEvent('invalid', this, msg);
32171 clearInvalid : function()
32173 var label = this.el.select('label', true).first();
32174 var icon = this.el.select('i.fa-star', true).first();
32180 this.fireEvent('valid', this);
32183 getName: function()
32193 * http://masonry.desandro.com
32195 * The idea is to render all the bricks based on vertical width...
32197 * The original code extends 'outlayer' - we might need to use that....
32203 * @class Roo.bootstrap.LayoutMasonry
32204 * @extends Roo.bootstrap.Component
32205 * Bootstrap Layout Masonry class
32208 * Create a new Element
32209 * @param {Object} config The config object
32212 Roo.bootstrap.LayoutMasonry = function(config){
32214 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
32218 Roo.bootstrap.LayoutMasonry.register(this);
32224 * Fire after layout the items
32225 * @param {Roo.bootstrap.LayoutMasonry} this
32226 * @param {Roo.EventObject} e
32233 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
32236 * @cfg {Boolean} isLayoutInstant = no animation?
32238 isLayoutInstant : false, // needed?
32241 * @cfg {Number} boxWidth width of the columns
32246 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
32251 * @cfg {Number} padWidth padding below box..
32256 * @cfg {Number} gutter gutter width..
32261 * @cfg {Number} maxCols maximum number of columns
32267 * @cfg {Boolean} isAutoInitial defalut true
32269 isAutoInitial : true,
32274 * @cfg {Boolean} isHorizontal defalut false
32276 isHorizontal : false,
32278 currentSize : null,
32284 bricks: null, //CompositeElement
32288 _isLayoutInited : false,
32290 // isAlternative : false, // only use for vertical layout...
32293 * @cfg {Number} alternativePadWidth padding below box..
32295 alternativePadWidth : 50,
32297 selectedBrick : [],
32299 getAutoCreate : function(){
32301 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
32305 cls: 'blog-masonary-wrapper ' + this.cls,
32307 cls : 'mas-boxes masonary'
32314 getChildContainer: function( )
32316 if (this.boxesEl) {
32317 return this.boxesEl;
32320 this.boxesEl = this.el.select('.mas-boxes').first();
32322 return this.boxesEl;
32326 initEvents : function()
32330 if(this.isAutoInitial){
32331 Roo.log('hook children rendered');
32332 this.on('childrenrendered', function() {
32333 Roo.log('children rendered');
32339 initial : function()
32341 this.selectedBrick = [];
32343 this.currentSize = this.el.getBox(true);
32345 Roo.EventManager.onWindowResize(this.resize, this);
32347 if(!this.isAutoInitial){
32355 //this.layout.defer(500,this);
32359 resize : function()
32361 var cs = this.el.getBox(true);
32364 this.currentSize.width == cs.width &&
32365 this.currentSize.x == cs.x &&
32366 this.currentSize.height == cs.height &&
32367 this.currentSize.y == cs.y
32369 Roo.log("no change in with or X or Y");
32373 this.currentSize = cs;
32379 layout : function()
32381 this._resetLayout();
32383 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32385 this.layoutItems( isInstant );
32387 this._isLayoutInited = true;
32389 this.fireEvent('layout', this);
32393 _resetLayout : function()
32395 if(this.isHorizontal){
32396 this.horizontalMeasureColumns();
32400 this.verticalMeasureColumns();
32404 verticalMeasureColumns : function()
32406 this.getContainerWidth();
32408 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
32409 // this.colWidth = Math.floor(this.containerWidth * 0.8);
32413 var boxWidth = this.boxWidth + this.padWidth;
32415 if(this.containerWidth < this.boxWidth){
32416 boxWidth = this.containerWidth
32419 var containerWidth = this.containerWidth;
32421 var cols = Math.floor(containerWidth / boxWidth);
32423 this.cols = Math.max( cols, 1 );
32425 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32427 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
32429 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
32431 this.colWidth = boxWidth + avail - this.padWidth;
32433 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
32434 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
32437 horizontalMeasureColumns : function()
32439 this.getContainerWidth();
32441 var boxWidth = this.boxWidth;
32443 if(this.containerWidth < boxWidth){
32444 boxWidth = this.containerWidth;
32447 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
32449 this.el.setHeight(boxWidth);
32453 getContainerWidth : function()
32455 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32458 layoutItems : function( isInstant )
32460 Roo.log(this.bricks);
32462 var items = Roo.apply([], this.bricks);
32464 if(this.isHorizontal){
32465 this._horizontalLayoutItems( items , isInstant );
32469 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
32470 // this._verticalAlternativeLayoutItems( items , isInstant );
32474 this._verticalLayoutItems( items , isInstant );
32478 _verticalLayoutItems : function ( items , isInstant)
32480 if ( !items || !items.length ) {
32485 ['xs', 'xs', 'xs', 'tall'],
32486 ['xs', 'xs', 'tall'],
32487 ['xs', 'xs', 'sm'],
32488 ['xs', 'xs', 'xs'],
32494 ['sm', 'xs', 'xs'],
32498 ['tall', 'xs', 'xs', 'xs'],
32499 ['tall', 'xs', 'xs'],
32511 Roo.each(items, function(item, k){
32513 switch (item.size) {
32514 // these layouts take up a full box,
32525 boxes.push([item]);
32548 var filterPattern = function(box, length)
32556 var pattern = box.slice(0, length);
32560 Roo.each(pattern, function(i){
32561 format.push(i.size);
32564 Roo.each(standard, function(s){
32566 if(String(s) != String(format)){
32575 if(!match && length == 1){
32580 filterPattern(box, length - 1);
32584 queue.push(pattern);
32586 box = box.slice(length, box.length);
32588 filterPattern(box, 4);
32594 Roo.each(boxes, function(box, k){
32600 if(box.length == 1){
32605 filterPattern(box, 4);
32609 this._processVerticalLayoutQueue( queue, isInstant );
32613 // _verticalAlternativeLayoutItems : function( items , isInstant )
32615 // if ( !items || !items.length ) {
32619 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
32623 _horizontalLayoutItems : function ( items , isInstant)
32625 if ( !items || !items.length || items.length < 3) {
32631 var eItems = items.slice(0, 3);
32633 items = items.slice(3, items.length);
32636 ['xs', 'xs', 'xs', 'wide'],
32637 ['xs', 'xs', 'wide'],
32638 ['xs', 'xs', 'sm'],
32639 ['xs', 'xs', 'xs'],
32645 ['sm', 'xs', 'xs'],
32649 ['wide', 'xs', 'xs', 'xs'],
32650 ['wide', 'xs', 'xs'],
32663 Roo.each(items, function(item, k){
32665 switch (item.size) {
32676 boxes.push([item]);
32700 var filterPattern = function(box, length)
32708 var pattern = box.slice(0, length);
32712 Roo.each(pattern, function(i){
32713 format.push(i.size);
32716 Roo.each(standard, function(s){
32718 if(String(s) != String(format)){
32727 if(!match && length == 1){
32732 filterPattern(box, length - 1);
32736 queue.push(pattern);
32738 box = box.slice(length, box.length);
32740 filterPattern(box, 4);
32746 Roo.each(boxes, function(box, k){
32752 if(box.length == 1){
32757 filterPattern(box, 4);
32764 var pos = this.el.getBox(true);
32768 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
32770 var hit_end = false;
32772 Roo.each(queue, function(box){
32776 Roo.each(box, function(b){
32778 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32788 Roo.each(box, function(b){
32790 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32793 mx = Math.max(mx, b.x);
32797 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
32801 Roo.each(box, function(b){
32803 b.el.setVisibilityMode(Roo.Element.DISPLAY);
32817 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
32820 /** Sets position of item in DOM
32821 * @param {Element} item
32822 * @param {Number} x - horizontal position
32823 * @param {Number} y - vertical position
32824 * @param {Boolean} isInstant - disables transitions
32826 _processVerticalLayoutQueue : function( queue, isInstant )
32828 var pos = this.el.getBox(true);
32833 for (var i = 0; i < this.cols; i++){
32837 Roo.each(queue, function(box, k){
32839 var col = k % this.cols;
32841 Roo.each(box, function(b,kk){
32843 b.el.position('absolute');
32845 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32846 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32848 if(b.size == 'md-left' || b.size == 'md-right'){
32849 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
32850 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32853 b.el.setWidth(width);
32854 b.el.setHeight(height);
32856 b.el.select('iframe',true).setSize(width,height);
32860 for (var i = 0; i < this.cols; i++){
32862 if(maxY[i] < maxY[col]){
32867 col = Math.min(col, i);
32871 x = pos.x + col * (this.colWidth + this.padWidth);
32875 var positions = [];
32877 switch (box.length){
32879 positions = this.getVerticalOneBoxColPositions(x, y, box);
32882 positions = this.getVerticalTwoBoxColPositions(x, y, box);
32885 positions = this.getVerticalThreeBoxColPositions(x, y, box);
32888 positions = this.getVerticalFourBoxColPositions(x, y, box);
32894 Roo.each(box, function(b,kk){
32896 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
32898 var sz = b.el.getSize();
32900 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
32908 for (var i = 0; i < this.cols; i++){
32909 mY = Math.max(mY, maxY[i]);
32912 this.el.setHeight(mY - pos.y);
32916 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
32918 // var pos = this.el.getBox(true);
32921 // var maxX = pos.right;
32923 // var maxHeight = 0;
32925 // Roo.each(items, function(item, k){
32929 // item.el.position('absolute');
32931 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
32933 // item.el.setWidth(width);
32935 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
32937 // item.el.setHeight(height);
32940 // item.el.setXY([x, y], isInstant ? false : true);
32942 // item.el.setXY([maxX - width, y], isInstant ? false : true);
32945 // y = y + height + this.alternativePadWidth;
32947 // maxHeight = maxHeight + height + this.alternativePadWidth;
32951 // this.el.setHeight(maxHeight);
32955 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
32957 var pos = this.el.getBox(true);
32962 var maxX = pos.right;
32964 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
32966 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
32968 Roo.each(queue, function(box, k){
32970 Roo.each(box, function(b, kk){
32972 b.el.position('absolute');
32974 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32975 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32977 if(b.size == 'md-left' || b.size == 'md-right'){
32978 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
32979 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32982 b.el.setWidth(width);
32983 b.el.setHeight(height);
32991 var positions = [];
32993 switch (box.length){
32995 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
32998 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
33001 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
33004 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
33010 Roo.each(box, function(b,kk){
33012 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33014 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
33022 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
33024 Roo.each(eItems, function(b,k){
33026 b.size = (k == 0) ? 'sm' : 'xs';
33027 b.x = (k == 0) ? 2 : 1;
33028 b.y = (k == 0) ? 2 : 1;
33030 b.el.position('absolute');
33032 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33034 b.el.setWidth(width);
33036 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33038 b.el.setHeight(height);
33042 var positions = [];
33045 x : maxX - this.unitWidth * 2 - this.gutter,
33050 x : maxX - this.unitWidth,
33051 y : minY + (this.unitWidth + this.gutter) * 2
33055 x : maxX - this.unitWidth * 3 - this.gutter * 2,
33059 Roo.each(eItems, function(b,k){
33061 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
33067 getVerticalOneBoxColPositions : function(x, y, box)
33071 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
33073 if(box[0].size == 'md-left'){
33077 if(box[0].size == 'md-right'){
33082 x : x + (this.unitWidth + this.gutter) * rand,
33089 getVerticalTwoBoxColPositions : function(x, y, box)
33093 if(box[0].size == 'xs'){
33097 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
33101 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
33115 x : x + (this.unitWidth + this.gutter) * 2,
33116 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
33123 getVerticalThreeBoxColPositions : function(x, y, box)
33127 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
33135 x : x + (this.unitWidth + this.gutter) * 1,
33140 x : x + (this.unitWidth + this.gutter) * 2,
33148 if(box[0].size == 'xs' && box[1].size == 'xs'){
33157 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
33161 x : x + (this.unitWidth + this.gutter) * 1,
33175 x : x + (this.unitWidth + this.gutter) * 2,
33180 x : x + (this.unitWidth + this.gutter) * 2,
33181 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
33188 getVerticalFourBoxColPositions : function(x, y, box)
33192 if(box[0].size == 'xs'){
33201 y : y + (this.unitHeight + this.gutter) * 1
33206 y : y + (this.unitHeight + this.gutter) * 2
33210 x : x + (this.unitWidth + this.gutter) * 1,
33224 x : x + (this.unitWidth + this.gutter) * 2,
33229 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
33230 y : y + (this.unitHeight + this.gutter) * 1
33234 x : x + (this.unitWidth + this.gutter) * 2,
33235 y : y + (this.unitWidth + this.gutter) * 2
33242 getHorizontalOneBoxColPositions : function(maxX, minY, box)
33246 if(box[0].size == 'md-left'){
33248 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
33255 if(box[0].size == 'md-right'){
33257 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
33258 y : minY + (this.unitWidth + this.gutter) * 1
33264 var rand = Math.floor(Math.random() * (4 - box[0].y));
33267 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33268 y : minY + (this.unitWidth + this.gutter) * rand
33275 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
33279 if(box[0].size == 'xs'){
33282 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33287 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33288 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
33296 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33301 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33302 y : minY + (this.unitWidth + this.gutter) * 2
33309 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
33313 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
33316 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33321 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33322 y : minY + (this.unitWidth + this.gutter) * 1
33326 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33327 y : minY + (this.unitWidth + this.gutter) * 2
33334 if(box[0].size == 'xs' && box[1].size == 'xs'){
33337 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33342 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33347 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33348 y : minY + (this.unitWidth + this.gutter) * 1
33356 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33361 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33362 y : minY + (this.unitWidth + this.gutter) * 2
33366 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33367 y : minY + (this.unitWidth + this.gutter) * 2
33374 getHorizontalFourBoxColPositions : function(maxX, minY, box)
33378 if(box[0].size == 'xs'){
33381 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33386 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33391 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33396 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
33397 y : minY + (this.unitWidth + this.gutter) * 1
33405 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
33410 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
33411 y : minY + (this.unitWidth + this.gutter) * 2
33415 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
33416 y : minY + (this.unitWidth + this.gutter) * 2
33420 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
33421 y : minY + (this.unitWidth + this.gutter) * 2
33429 * remove a Masonry Brick
33430 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
33432 removeBrick : function(brick_id)
33438 for (var i = 0; i<this.bricks.length; i++) {
33439 if (this.bricks[i].id == brick_id) {
33440 this.bricks.splice(i,1);
33441 this.el.dom.removeChild(Roo.get(brick_id).dom);
33448 * adds a Masonry Brick
33449 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33451 addBrick : function(cfg)
33453 var cn = new Roo.bootstrap.MasonryBrick(cfg);
33454 //this.register(cn);
33455 cn.parentId = this.id;
33456 cn.render(this.el);
33461 * register a Masonry Brick
33462 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33465 register : function(brick)
33467 this.bricks.push(brick);
33468 brick.masonryId = this.id;
33472 * clear all the Masonry Brick
33474 clearAll : function()
33477 //this.getChildContainer().dom.innerHTML = "";
33478 this.el.dom.innerHTML = '';
33481 getSelected : function()
33483 if (!this.selectedBrick) {
33487 return this.selectedBrick;
33491 Roo.apply(Roo.bootstrap.LayoutMasonry, {
33495 * register a Masonry Layout
33496 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
33499 register : function(layout)
33501 this.groups[layout.id] = layout;
33504 * fetch a Masonry Layout based on the masonry layout ID
33505 * @param {string} the masonry layout to add
33506 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
33509 get: function(layout_id) {
33510 if (typeof(this.groups[layout_id]) == 'undefined') {
33513 return this.groups[layout_id] ;
33525 * http://masonry.desandro.com
33527 * The idea is to render all the bricks based on vertical width...
33529 * The original code extends 'outlayer' - we might need to use that....
33535 * @class Roo.bootstrap.LayoutMasonryAuto
33536 * @extends Roo.bootstrap.Component
33537 * Bootstrap Layout Masonry class
33540 * Create a new Element
33541 * @param {Object} config The config object
33544 Roo.bootstrap.LayoutMasonryAuto = function(config){
33545 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
33548 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
33551 * @cfg {Boolean} isFitWidth - resize the width..
33553 isFitWidth : false, // options..
33555 * @cfg {Boolean} isOriginLeft = left align?
33557 isOriginLeft : true,
33559 * @cfg {Boolean} isOriginTop = top align?
33561 isOriginTop : false,
33563 * @cfg {Boolean} isLayoutInstant = no animation?
33565 isLayoutInstant : false, // needed?
33567 * @cfg {Boolean} isResizingContainer = not sure if this is used..
33569 isResizingContainer : true,
33571 * @cfg {Number} columnWidth width of the columns
33577 * @cfg {Number} maxCols maximum number of columns
33582 * @cfg {Number} padHeight padding below box..
33588 * @cfg {Boolean} isAutoInitial defalut true
33591 isAutoInitial : true,
33597 initialColumnWidth : 0,
33598 currentSize : null,
33600 colYs : null, // array.
33607 bricks: null, //CompositeElement
33608 cols : 0, // array?
33609 // element : null, // wrapped now this.el
33610 _isLayoutInited : null,
33613 getAutoCreate : function(){
33617 cls: 'blog-masonary-wrapper ' + this.cls,
33619 cls : 'mas-boxes masonary'
33626 getChildContainer: function( )
33628 if (this.boxesEl) {
33629 return this.boxesEl;
33632 this.boxesEl = this.el.select('.mas-boxes').first();
33634 return this.boxesEl;
33638 initEvents : function()
33642 if(this.isAutoInitial){
33643 Roo.log('hook children rendered');
33644 this.on('childrenrendered', function() {
33645 Roo.log('children rendered');
33652 initial : function()
33654 this.reloadItems();
33656 this.currentSize = this.el.getBox(true);
33658 /// was window resize... - let's see if this works..
33659 Roo.EventManager.onWindowResize(this.resize, this);
33661 if(!this.isAutoInitial){
33666 this.layout.defer(500,this);
33669 reloadItems: function()
33671 this.bricks = this.el.select('.masonry-brick', true);
33673 this.bricks.each(function(b) {
33674 //Roo.log(b.getSize());
33675 if (!b.attr('originalwidth')) {
33676 b.attr('originalwidth', b.getSize().width);
33681 Roo.log(this.bricks.elements.length);
33684 resize : function()
33687 var cs = this.el.getBox(true);
33689 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
33690 Roo.log("no change in with or X");
33693 this.currentSize = cs;
33697 layout : function()
33700 this._resetLayout();
33701 //this._manageStamps();
33703 // don't animate first layout
33704 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
33705 this.layoutItems( isInstant );
33707 // flag for initalized
33708 this._isLayoutInited = true;
33711 layoutItems : function( isInstant )
33713 //var items = this._getItemsForLayout( this.items );
33714 // original code supports filtering layout items.. we just ignore it..
33716 this._layoutItems( this.bricks , isInstant );
33718 this._postLayout();
33720 _layoutItems : function ( items , isInstant)
33722 //this.fireEvent( 'layout', this, items );
33725 if ( !items || !items.elements.length ) {
33726 // no items, emit event with empty array
33731 items.each(function(item) {
33732 Roo.log("layout item");
33734 // get x/y object from method
33735 var position = this._getItemLayoutPosition( item );
33737 position.item = item;
33738 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
33739 queue.push( position );
33742 this._processLayoutQueue( queue );
33744 /** Sets position of item in DOM
33745 * @param {Element} item
33746 * @param {Number} x - horizontal position
33747 * @param {Number} y - vertical position
33748 * @param {Boolean} isInstant - disables transitions
33750 _processLayoutQueue : function( queue )
33752 for ( var i=0, len = queue.length; i < len; i++ ) {
33753 var obj = queue[i];
33754 obj.item.position('absolute');
33755 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
33761 * Any logic you want to do after each layout,
33762 * i.e. size the container
33764 _postLayout : function()
33766 this.resizeContainer();
33769 resizeContainer : function()
33771 if ( !this.isResizingContainer ) {
33774 var size = this._getContainerSize();
33776 this.el.setSize(size.width,size.height);
33777 this.boxesEl.setSize(size.width,size.height);
33783 _resetLayout : function()
33785 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
33786 this.colWidth = this.el.getWidth();
33787 //this.gutter = this.el.getWidth();
33789 this.measureColumns();
33795 this.colYs.push( 0 );
33801 measureColumns : function()
33803 this.getContainerWidth();
33804 // if columnWidth is 0, default to outerWidth of first item
33805 if ( !this.columnWidth ) {
33806 var firstItem = this.bricks.first();
33807 Roo.log(firstItem);
33808 this.columnWidth = this.containerWidth;
33809 if (firstItem && firstItem.attr('originalwidth') ) {
33810 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
33812 // columnWidth fall back to item of first element
33813 Roo.log("set column width?");
33814 this.initialColumnWidth = this.columnWidth ;
33816 // if first elem has no width, default to size of container
33821 if (this.initialColumnWidth) {
33822 this.columnWidth = this.initialColumnWidth;
33827 // column width is fixed at the top - however if container width get's smaller we should
33830 // this bit calcs how man columns..
33832 var columnWidth = this.columnWidth += this.gutter;
33834 // calculate columns
33835 var containerWidth = this.containerWidth + this.gutter;
33837 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
33838 // fix rounding errors, typically with gutters
33839 var excess = columnWidth - containerWidth % columnWidth;
33842 // if overshoot is less than a pixel, round up, otherwise floor it
33843 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
33844 cols = Math[ mathMethod ]( cols );
33845 this.cols = Math.max( cols, 1 );
33846 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
33848 // padding positioning..
33849 var totalColWidth = this.cols * this.columnWidth;
33850 var padavail = this.containerWidth - totalColWidth;
33851 // so for 2 columns - we need 3 'pads'
33853 var padNeeded = (1+this.cols) * this.padWidth;
33855 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
33857 this.columnWidth += padExtra
33858 //this.padWidth = Math.floor(padavail / ( this.cols));
33860 // adjust colum width so that padding is fixed??
33862 // we have 3 columns ... total = width * 3
33863 // we have X left over... that should be used by
33865 //if (this.expandC) {
33873 getContainerWidth : function()
33875 /* // container is parent if fit width
33876 var container = this.isFitWidth ? this.element.parentNode : this.element;
33877 // check that this.size and size are there
33878 // IE8 triggers resize on body size change, so they might not be
33880 var size = getSize( container ); //FIXME
33881 this.containerWidth = size && size.innerWidth; //FIXME
33884 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
33888 _getItemLayoutPosition : function( item ) // what is item?
33890 // we resize the item to our columnWidth..
33892 item.setWidth(this.columnWidth);
33893 item.autoBoxAdjust = false;
33895 var sz = item.getSize();
33897 // how many columns does this brick span
33898 var remainder = this.containerWidth % this.columnWidth;
33900 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
33901 // round if off by 1 pixel, otherwise use ceil
33902 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
33903 colSpan = Math.min( colSpan, this.cols );
33905 // normally this should be '1' as we dont' currently allow multi width columns..
33907 var colGroup = this._getColGroup( colSpan );
33908 // get the minimum Y value from the columns
33909 var minimumY = Math.min.apply( Math, colGroup );
33910 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
33912 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
33914 // position the brick
33916 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
33917 y: this.currentSize.y + minimumY + this.padHeight
33921 // apply setHeight to necessary columns
33922 var setHeight = minimumY + sz.height + this.padHeight;
33923 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
33925 var setSpan = this.cols + 1 - colGroup.length;
33926 for ( var i = 0; i < setSpan; i++ ) {
33927 this.colYs[ shortColIndex + i ] = setHeight ;
33934 * @param {Number} colSpan - number of columns the element spans
33935 * @returns {Array} colGroup
33937 _getColGroup : function( colSpan )
33939 if ( colSpan < 2 ) {
33940 // if brick spans only one column, use all the column Ys
33945 // how many different places could this brick fit horizontally
33946 var groupCount = this.cols + 1 - colSpan;
33947 // for each group potential horizontal position
33948 for ( var i = 0; i < groupCount; i++ ) {
33949 // make an array of colY values for that one group
33950 var groupColYs = this.colYs.slice( i, i + colSpan );
33951 // and get the max value of the array
33952 colGroup[i] = Math.max.apply( Math, groupColYs );
33957 _manageStamp : function( stamp )
33959 var stampSize = stamp.getSize();
33960 var offset = stamp.getBox();
33961 // get the columns that this stamp affects
33962 var firstX = this.isOriginLeft ? offset.x : offset.right;
33963 var lastX = firstX + stampSize.width;
33964 var firstCol = Math.floor( firstX / this.columnWidth );
33965 firstCol = Math.max( 0, firstCol );
33967 var lastCol = Math.floor( lastX / this.columnWidth );
33968 // lastCol should not go over if multiple of columnWidth #425
33969 lastCol -= lastX % this.columnWidth ? 0 : 1;
33970 lastCol = Math.min( this.cols - 1, lastCol );
33972 // set colYs to bottom of the stamp
33973 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
33976 for ( var i = firstCol; i <= lastCol; i++ ) {
33977 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
33982 _getContainerSize : function()
33984 this.maxY = Math.max.apply( Math, this.colYs );
33989 if ( this.isFitWidth ) {
33990 size.width = this._getContainerFitWidth();
33996 _getContainerFitWidth : function()
33998 var unusedCols = 0;
33999 // count unused columns
34002 if ( this.colYs[i] !== 0 ) {
34007 // fit container to columns that have been used
34008 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
34011 needsResizeLayout : function()
34013 var previousWidth = this.containerWidth;
34014 this.getContainerWidth();
34015 return previousWidth !== this.containerWidth;
34030 * @class Roo.bootstrap.MasonryBrick
34031 * @extends Roo.bootstrap.Component
34032 * Bootstrap MasonryBrick class
34035 * Create a new MasonryBrick
34036 * @param {Object} config The config object
34039 Roo.bootstrap.MasonryBrick = function(config){
34041 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
34043 Roo.bootstrap.MasonryBrick.register(this);
34049 * When a MasonryBrick is clcik
34050 * @param {Roo.bootstrap.MasonryBrick} this
34051 * @param {Roo.EventObject} e
34057 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
34060 * @cfg {String} title
34064 * @cfg {String} html
34068 * @cfg {String} bgimage
34072 * @cfg {String} videourl
34076 * @cfg {String} cls
34080 * @cfg {String} href
34084 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
34089 * @cfg {String} placetitle (center|bottom)
34094 * @cfg {Boolean} isFitContainer defalut true
34096 isFitContainer : true,
34099 * @cfg {Boolean} preventDefault defalut false
34101 preventDefault : false,
34104 * @cfg {Boolean} inverse defalut false
34106 maskInverse : false,
34108 getAutoCreate : function()
34110 if(!this.isFitContainer){
34111 return this.getSplitAutoCreate();
34114 var cls = 'masonry-brick masonry-brick-full';
34116 if(this.href.length){
34117 cls += ' masonry-brick-link';
34120 if(this.bgimage.length){
34121 cls += ' masonry-brick-image';
34124 if(this.maskInverse){
34125 cls += ' mask-inverse';
34128 if(!this.html.length && !this.maskInverse && !this.videourl.length){
34129 cls += ' enable-mask';
34133 cls += ' masonry-' + this.size + '-brick';
34136 if(this.placetitle.length){
34138 switch (this.placetitle) {
34140 cls += ' masonry-center-title';
34143 cls += ' masonry-bottom-title';
34150 if(!this.html.length && !this.bgimage.length){
34151 cls += ' masonry-center-title';
34154 if(!this.html.length && this.bgimage.length){
34155 cls += ' masonry-bottom-title';
34160 cls += ' ' + this.cls;
34164 tag: (this.href.length) ? 'a' : 'div',
34169 cls: 'masonry-brick-mask'
34173 cls: 'masonry-brick-paragraph',
34179 if(this.href.length){
34180 cfg.href = this.href;
34183 var cn = cfg.cn[1].cn;
34185 if(this.title.length){
34188 cls: 'masonry-brick-title',
34193 if(this.html.length){
34196 cls: 'masonry-brick-text',
34201 if (!this.title.length && !this.html.length) {
34202 cfg.cn[1].cls += ' hide';
34205 if(this.bgimage.length){
34208 cls: 'masonry-brick-image-view',
34213 if(this.videourl.length){
34214 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
34215 // youtube support only?
34218 cls: 'masonry-brick-image-view',
34221 allowfullscreen : true
34229 getSplitAutoCreate : function()
34231 var cls = 'masonry-brick masonry-brick-split';
34233 if(this.href.length){
34234 cls += ' masonry-brick-link';
34237 if(this.bgimage.length){
34238 cls += ' masonry-brick-image';
34242 cls += ' masonry-' + this.size + '-brick';
34245 switch (this.placetitle) {
34247 cls += ' masonry-center-title';
34250 cls += ' masonry-bottom-title';
34253 if(!this.bgimage.length){
34254 cls += ' masonry-center-title';
34257 if(this.bgimage.length){
34258 cls += ' masonry-bottom-title';
34264 cls += ' ' + this.cls;
34268 tag: (this.href.length) ? 'a' : 'div',
34273 cls: 'masonry-brick-split-head',
34277 cls: 'masonry-brick-paragraph',
34284 cls: 'masonry-brick-split-body',
34290 if(this.href.length){
34291 cfg.href = this.href;
34294 if(this.title.length){
34295 cfg.cn[0].cn[0].cn.push({
34297 cls: 'masonry-brick-title',
34302 if(this.html.length){
34303 cfg.cn[1].cn.push({
34305 cls: 'masonry-brick-text',
34310 if(this.bgimage.length){
34311 cfg.cn[0].cn.push({
34313 cls: 'masonry-brick-image-view',
34318 if(this.videourl.length){
34319 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
34320 // youtube support only?
34321 cfg.cn[0].cn.cn.push({
34323 cls: 'masonry-brick-image-view',
34326 allowfullscreen : true
34333 initEvents: function()
34335 switch (this.size) {
34368 this.el.on('touchstart', this.onTouchStart, this);
34369 this.el.on('touchmove', this.onTouchMove, this);
34370 this.el.on('touchend', this.onTouchEnd, this);
34371 this.el.on('contextmenu', this.onContextMenu, this);
34373 this.el.on('mouseenter' ,this.enter, this);
34374 this.el.on('mouseleave', this.leave, this);
34375 this.el.on('click', this.onClick, this);
34378 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
34379 this.parent().bricks.push(this);
34384 onClick: function(e, el)
34386 var time = this.endTimer - this.startTimer;
34387 // Roo.log(e.preventDefault());
34390 e.preventDefault();
34395 if(!this.preventDefault){
34399 e.preventDefault();
34401 if (this.activeClass != '') {
34402 this.selectBrick();
34405 this.fireEvent('click', this, e);
34408 enter: function(e, el)
34410 e.preventDefault();
34412 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
34416 if(this.bgimage.length && this.html.length){
34417 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
34421 leave: function(e, el)
34423 e.preventDefault();
34425 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
34429 if(this.bgimage.length && this.html.length){
34430 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
34434 onTouchStart: function(e, el)
34436 // e.preventDefault();
34438 this.touchmoved = false;
34440 if(!this.isFitContainer){
34444 if(!this.bgimage.length || !this.html.length){
34448 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
34450 this.timer = new Date().getTime();
34454 onTouchMove: function(e, el)
34456 this.touchmoved = true;
34459 onContextMenu : function(e,el)
34461 e.preventDefault();
34462 e.stopPropagation();
34466 onTouchEnd: function(e, el)
34468 // e.preventDefault();
34470 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
34477 if(!this.bgimage.length || !this.html.length){
34479 if(this.href.length){
34480 window.location.href = this.href;
34486 if(!this.isFitContainer){
34490 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
34492 window.location.href = this.href;
34495 //selection on single brick only
34496 selectBrick : function() {
34498 if (!this.parentId) {
34502 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
34503 var index = m.selectedBrick.indexOf(this.id);
34506 m.selectedBrick.splice(index,1);
34507 this.el.removeClass(this.activeClass);
34511 for(var i = 0; i < m.selectedBrick.length; i++) {
34512 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
34513 b.el.removeClass(b.activeClass);
34516 m.selectedBrick = [];
34518 m.selectedBrick.push(this.id);
34519 this.el.addClass(this.activeClass);
34523 isSelected : function(){
34524 return this.el.hasClass(this.activeClass);
34529 Roo.apply(Roo.bootstrap.MasonryBrick, {
34532 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
34534 * register a Masonry Brick
34535 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34538 register : function(brick)
34540 //this.groups[brick.id] = brick;
34541 this.groups.add(brick.id, brick);
34544 * fetch a masonry brick based on the masonry brick ID
34545 * @param {string} the masonry brick to add
34546 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
34549 get: function(brick_id)
34551 // if (typeof(this.groups[brick_id]) == 'undefined') {
34554 // return this.groups[brick_id] ;
34556 if(this.groups.key(brick_id)) {
34557 return this.groups.key(brick_id);
34575 * @class Roo.bootstrap.Brick
34576 * @extends Roo.bootstrap.Component
34577 * Bootstrap Brick class
34580 * Create a new Brick
34581 * @param {Object} config The config object
34584 Roo.bootstrap.Brick = function(config){
34585 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
34591 * When a Brick is click
34592 * @param {Roo.bootstrap.Brick} this
34593 * @param {Roo.EventObject} e
34599 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
34602 * @cfg {String} title
34606 * @cfg {String} html
34610 * @cfg {String} bgimage
34614 * @cfg {String} cls
34618 * @cfg {String} href
34622 * @cfg {String} video
34626 * @cfg {Boolean} square
34630 getAutoCreate : function()
34632 var cls = 'roo-brick';
34634 if(this.href.length){
34635 cls += ' roo-brick-link';
34638 if(this.bgimage.length){
34639 cls += ' roo-brick-image';
34642 if(!this.html.length && !this.bgimage.length){
34643 cls += ' roo-brick-center-title';
34646 if(!this.html.length && this.bgimage.length){
34647 cls += ' roo-brick-bottom-title';
34651 cls += ' ' + this.cls;
34655 tag: (this.href.length) ? 'a' : 'div',
34660 cls: 'roo-brick-paragraph',
34666 if(this.href.length){
34667 cfg.href = this.href;
34670 var cn = cfg.cn[0].cn;
34672 if(this.title.length){
34675 cls: 'roo-brick-title',
34680 if(this.html.length){
34683 cls: 'roo-brick-text',
34690 if(this.bgimage.length){
34693 cls: 'roo-brick-image-view',
34701 initEvents: function()
34703 if(this.title.length || this.html.length){
34704 this.el.on('mouseenter' ,this.enter, this);
34705 this.el.on('mouseleave', this.leave, this);
34708 Roo.EventManager.onWindowResize(this.resize, this);
34710 if(this.bgimage.length){
34711 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
34712 this.imageEl.on('load', this.onImageLoad, this);
34719 onImageLoad : function()
34724 resize : function()
34726 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
34728 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
34730 if(this.bgimage.length){
34731 var image = this.el.select('.roo-brick-image-view', true).first();
34733 image.setWidth(paragraph.getWidth());
34736 image.setHeight(paragraph.getWidth());
34739 this.el.setHeight(image.getHeight());
34740 paragraph.setHeight(image.getHeight());
34746 enter: function(e, el)
34748 e.preventDefault();
34750 if(this.bgimage.length){
34751 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
34752 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
34756 leave: function(e, el)
34758 e.preventDefault();
34760 if(this.bgimage.length){
34761 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
34762 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
34777 * @class Roo.bootstrap.NumberField
34778 * @extends Roo.bootstrap.Input
34779 * Bootstrap NumberField class
34785 * Create a new NumberField
34786 * @param {Object} config The config object
34789 Roo.bootstrap.NumberField = function(config){
34790 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
34793 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
34796 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
34798 allowDecimals : true,
34800 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
34802 decimalSeparator : ".",
34804 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
34806 decimalPrecision : 2,
34808 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
34810 allowNegative : true,
34813 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
34817 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
34819 minValue : Number.NEGATIVE_INFINITY,
34821 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
34823 maxValue : Number.MAX_VALUE,
34825 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
34827 minText : "The minimum value for this field is {0}",
34829 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
34831 maxText : "The maximum value for this field is {0}",
34833 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
34834 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
34836 nanText : "{0} is not a valid number",
34838 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
34840 thousandsDelimiter : false,
34842 * @cfg {String} valueAlign alignment of value
34844 valueAlign : "left",
34846 getAutoCreate : function()
34848 var hiddenInput = {
34852 cls: 'hidden-number-input'
34856 hiddenInput.name = this.name;
34861 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
34863 this.name = hiddenInput.name;
34865 if(cfg.cn.length > 0) {
34866 cfg.cn.push(hiddenInput);
34873 initEvents : function()
34875 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
34877 var allowed = "0123456789";
34879 if(this.allowDecimals){
34880 allowed += this.decimalSeparator;
34883 if(this.allowNegative){
34887 if(this.thousandsDelimiter) {
34891 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
34893 var keyPress = function(e){
34895 var k = e.getKey();
34897 var c = e.getCharCode();
34900 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
34901 allowed.indexOf(String.fromCharCode(c)) === -1
34907 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
34911 if(allowed.indexOf(String.fromCharCode(c)) === -1){
34916 this.el.on("keypress", keyPress, this);
34919 validateValue : function(value)
34922 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
34926 var num = this.parseValue(value);
34929 this.markInvalid(String.format(this.nanText, value));
34933 if(num < this.minValue){
34934 this.markInvalid(String.format(this.minText, this.minValue));
34938 if(num > this.maxValue){
34939 this.markInvalid(String.format(this.maxText, this.maxValue));
34946 getValue : function()
34948 var v = this.hiddenEl().getValue();
34950 return this.fixPrecision(this.parseValue(v));
34953 parseValue : function(value)
34955 if(this.thousandsDelimiter) {
34957 r = new RegExp(",", "g");
34958 value = value.replace(r, "");
34961 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
34962 return isNaN(value) ? '' : value;
34965 fixPrecision : function(value)
34967 if(this.thousandsDelimiter) {
34969 r = new RegExp(",", "g");
34970 value = value.replace(r, "");
34973 var nan = isNaN(value);
34975 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
34976 return nan ? '' : value;
34978 return parseFloat(value).toFixed(this.decimalPrecision);
34981 setValue : function(v)
34983 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
34989 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
34991 this.inputEl().dom.value = (v == '') ? '' :
34992 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
34994 if(!this.allowZero && v === '0') {
34995 this.hiddenEl().dom.value = '';
34996 this.inputEl().dom.value = '';
35003 decimalPrecisionFcn : function(v)
35005 return Math.floor(v);
35008 beforeBlur : function()
35010 var v = this.parseValue(this.getRawValue());
35012 if(v || v === 0 || v === ''){
35017 hiddenEl : function()
35019 return this.el.select('input.hidden-number-input',true).first();
35031 * @class Roo.bootstrap.DocumentSlider
35032 * @extends Roo.bootstrap.Component
35033 * Bootstrap DocumentSlider class
35036 * Create a new DocumentViewer
35037 * @param {Object} config The config object
35040 Roo.bootstrap.DocumentSlider = function(config){
35041 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
35048 * Fire after initEvent
35049 * @param {Roo.bootstrap.DocumentSlider} this
35054 * Fire after update
35055 * @param {Roo.bootstrap.DocumentSlider} this
35061 * @param {Roo.bootstrap.DocumentSlider} this
35067 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
35073 getAutoCreate : function()
35077 cls : 'roo-document-slider',
35081 cls : 'roo-document-slider-header',
35085 cls : 'roo-document-slider-header-title'
35091 cls : 'roo-document-slider-body',
35095 cls : 'roo-document-slider-prev',
35099 cls : 'fa fa-chevron-left'
35105 cls : 'roo-document-slider-thumb',
35109 cls : 'roo-document-slider-image'
35115 cls : 'roo-document-slider-next',
35119 cls : 'fa fa-chevron-right'
35131 initEvents : function()
35133 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
35134 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
35136 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
35137 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
35139 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
35140 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
35142 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
35143 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
35145 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
35146 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
35148 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
35149 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35151 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
35152 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35154 this.thumbEl.on('click', this.onClick, this);
35156 this.prevIndicator.on('click', this.prev, this);
35158 this.nextIndicator.on('click', this.next, this);
35162 initial : function()
35164 if(this.files.length){
35165 this.indicator = 1;
35169 this.fireEvent('initial', this);
35172 update : function()
35174 this.imageEl.attr('src', this.files[this.indicator - 1]);
35176 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
35178 this.prevIndicator.show();
35180 if(this.indicator == 1){
35181 this.prevIndicator.hide();
35184 this.nextIndicator.show();
35186 if(this.indicator == this.files.length){
35187 this.nextIndicator.hide();
35190 this.thumbEl.scrollTo('top');
35192 this.fireEvent('update', this);
35195 onClick : function(e)
35197 e.preventDefault();
35199 this.fireEvent('click', this);
35204 e.preventDefault();
35206 this.indicator = Math.max(1, this.indicator - 1);
35213 e.preventDefault();
35215 this.indicator = Math.min(this.files.length, this.indicator + 1);
35229 * @class Roo.bootstrap.RadioSet
35230 * @extends Roo.bootstrap.Input
35231 * Bootstrap RadioSet class
35232 * @cfg {String} indicatorpos (left|right) default left
35233 * @cfg {Boolean} inline (true|false) inline the element (default true)
35234 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
35236 * Create a new RadioSet
35237 * @param {Object} config The config object
35240 Roo.bootstrap.RadioSet = function(config){
35242 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
35246 Roo.bootstrap.RadioSet.register(this);
35251 * Fires when the element is checked or unchecked.
35252 * @param {Roo.bootstrap.RadioSet} this This radio
35253 * @param {Roo.bootstrap.Radio} item The checked item
35258 * Fires when the element is click.
35259 * @param {Roo.bootstrap.RadioSet} this This radio set
35260 * @param {Roo.bootstrap.Radio} item The checked item
35261 * @param {Roo.EventObject} e The event object
35268 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
35276 indicatorpos : 'left',
35278 getAutoCreate : function()
35282 cls : 'roo-radio-set-label',
35286 html : this.fieldLabel
35290 if (Roo.bootstrap.version == 3) {
35293 if(this.indicatorpos == 'left'){
35296 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
35297 tooltip : 'This field is required'
35302 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
35303 tooltip : 'This field is required'
35309 cls : 'roo-radio-set-items'
35312 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
35314 if (align === 'left' && this.fieldLabel.length) {
35317 cls : "roo-radio-set-right",
35323 if(this.labelWidth > 12){
35324 label.style = "width: " + this.labelWidth + 'px';
35327 if(this.labelWidth < 13 && this.labelmd == 0){
35328 this.labelmd = this.labelWidth;
35331 if(this.labellg > 0){
35332 label.cls += ' col-lg-' + this.labellg;
35333 items.cls += ' col-lg-' + (12 - this.labellg);
35336 if(this.labelmd > 0){
35337 label.cls += ' col-md-' + this.labelmd;
35338 items.cls += ' col-md-' + (12 - this.labelmd);
35341 if(this.labelsm > 0){
35342 label.cls += ' col-sm-' + this.labelsm;
35343 items.cls += ' col-sm-' + (12 - this.labelsm);
35346 if(this.labelxs > 0){
35347 label.cls += ' col-xs-' + this.labelxs;
35348 items.cls += ' col-xs-' + (12 - this.labelxs);
35354 cls : 'roo-radio-set',
35358 cls : 'roo-radio-set-input',
35361 value : this.value ? this.value : ''
35368 if(this.weight.length){
35369 cfg.cls += ' roo-radio-' + this.weight;
35373 cfg.cls += ' roo-radio-set-inline';
35377 ['xs','sm','md','lg'].map(function(size){
35378 if (settings[size]) {
35379 cfg.cls += ' col-' + size + '-' + settings[size];
35387 initEvents : function()
35389 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
35390 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
35392 if(!this.fieldLabel.length){
35393 this.labelEl.hide();
35396 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
35397 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
35399 this.indicator = this.indicatorEl();
35401 if(this.indicator){
35402 this.indicator.addClass('invisible');
35405 this.originalValue = this.getValue();
35409 inputEl: function ()
35411 return this.el.select('.roo-radio-set-input', true).first();
35414 getChildContainer : function()
35416 return this.itemsEl;
35419 register : function(item)
35421 this.radioes.push(item);
35425 validate : function()
35427 if(this.getVisibilityEl().hasClass('hidden')){
35433 Roo.each(this.radioes, function(i){
35442 if(this.allowBlank) {
35446 if(this.disabled || valid){
35451 this.markInvalid();
35456 markValid : function()
35458 if(this.labelEl.isVisible(true) && this.indicatorEl()){
35459 this.indicatorEl().removeClass('visible');
35460 this.indicatorEl().addClass('invisible');
35464 if (Roo.bootstrap.version == 3) {
35465 this.el.removeClass([this.invalidClass, this.validClass]);
35466 this.el.addClass(this.validClass);
35468 this.el.removeClass(['is-invalid','is-valid']);
35469 this.el.addClass(['is-valid']);
35471 this.fireEvent('valid', this);
35474 markInvalid : function(msg)
35476 if(this.allowBlank || this.disabled){
35480 if(this.labelEl.isVisible(true) && this.indicatorEl()){
35481 this.indicatorEl().removeClass('invisible');
35482 this.indicatorEl().addClass('visible');
35484 if (Roo.bootstrap.version == 3) {
35485 this.el.removeClass([this.invalidClass, this.validClass]);
35486 this.el.addClass(this.invalidClass);
35488 this.el.removeClass(['is-invalid','is-valid']);
35489 this.el.addClass(['is-invalid']);
35492 this.fireEvent('invalid', this, msg);
35496 setValue : function(v, suppressEvent)
35498 if(this.value === v){
35505 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
35508 Roo.each(this.radioes, function(i){
35510 i.el.removeClass('checked');
35513 Roo.each(this.radioes, function(i){
35515 if(i.value === v || i.value.toString() === v.toString()){
35517 i.el.addClass('checked');
35519 if(suppressEvent !== true){
35520 this.fireEvent('check', this, i);
35531 clearInvalid : function(){
35533 if(!this.el || this.preventMark){
35537 this.el.removeClass([this.invalidClass]);
35539 this.fireEvent('valid', this);
35544 Roo.apply(Roo.bootstrap.RadioSet, {
35548 register : function(set)
35550 this.groups[set.name] = set;
35553 get: function(name)
35555 if (typeof(this.groups[name]) == 'undefined') {
35559 return this.groups[name] ;
35565 * Ext JS Library 1.1.1
35566 * Copyright(c) 2006-2007, Ext JS, LLC.
35568 * Originally Released Under LGPL - original licence link has changed is not relivant.
35571 * <script type="text/javascript">
35576 * @class Roo.bootstrap.SplitBar
35577 * @extends Roo.util.Observable
35578 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
35582 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
35583 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
35584 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
35585 split.minSize = 100;
35586 split.maxSize = 600;
35587 split.animate = true;
35588 split.on('moved', splitterMoved);
35591 * Create a new SplitBar
35592 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
35593 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
35594 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
35595 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
35596 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
35597 position of the SplitBar).
35599 Roo.bootstrap.SplitBar = function(cfg){
35604 // dragElement : elm
35605 // resizingElement: el,
35607 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
35608 // placement : Roo.bootstrap.SplitBar.LEFT ,
35609 // existingProxy ???
35612 this.el = Roo.get(cfg.dragElement, true);
35613 this.el.dom.unselectable = "on";
35615 this.resizingEl = Roo.get(cfg.resizingElement, true);
35619 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
35620 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
35623 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
35626 * The minimum size of the resizing element. (Defaults to 0)
35632 * The maximum size of the resizing element. (Defaults to 2000)
35635 this.maxSize = 2000;
35638 * Whether to animate the transition to the new size
35641 this.animate = false;
35644 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
35647 this.useShim = false;
35652 if(!cfg.existingProxy){
35654 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
35656 this.proxy = Roo.get(cfg.existingProxy).dom;
35659 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
35662 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
35665 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
35668 this.dragSpecs = {};
35671 * @private The adapter to use to positon and resize elements
35673 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
35674 this.adapter.init(this);
35676 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35678 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
35679 this.el.addClass("roo-splitbar-h");
35682 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
35683 this.el.addClass("roo-splitbar-v");
35689 * Fires when the splitter is moved (alias for {@link #event-moved})
35690 * @param {Roo.bootstrap.SplitBar} this
35691 * @param {Number} newSize the new width or height
35696 * Fires when the splitter is moved
35697 * @param {Roo.bootstrap.SplitBar} this
35698 * @param {Number} newSize the new width or height
35702 * @event beforeresize
35703 * Fires before the splitter is dragged
35704 * @param {Roo.bootstrap.SplitBar} this
35706 "beforeresize" : true,
35708 "beforeapply" : true
35711 Roo.util.Observable.call(this);
35714 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
35715 onStartProxyDrag : function(x, y){
35716 this.fireEvent("beforeresize", this);
35718 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
35720 o.enableDisplayMode("block");
35721 // all splitbars share the same overlay
35722 Roo.bootstrap.SplitBar.prototype.overlay = o;
35724 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
35725 this.overlay.show();
35726 Roo.get(this.proxy).setDisplayed("block");
35727 var size = this.adapter.getElementSize(this);
35728 this.activeMinSize = this.getMinimumSize();;
35729 this.activeMaxSize = this.getMaximumSize();;
35730 var c1 = size - this.activeMinSize;
35731 var c2 = Math.max(this.activeMaxSize - size, 0);
35732 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35733 this.dd.resetConstraints();
35734 this.dd.setXConstraint(
35735 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
35736 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
35738 this.dd.setYConstraint(0, 0);
35740 this.dd.resetConstraints();
35741 this.dd.setXConstraint(0, 0);
35742 this.dd.setYConstraint(
35743 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
35744 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
35747 this.dragSpecs.startSize = size;
35748 this.dragSpecs.startPoint = [x, y];
35749 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
35753 * @private Called after the drag operation by the DDProxy
35755 onEndProxyDrag : function(e){
35756 Roo.get(this.proxy).setDisplayed(false);
35757 var endPoint = Roo.lib.Event.getXY(e);
35759 this.overlay.hide();
35762 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35763 newSize = this.dragSpecs.startSize +
35764 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
35765 endPoint[0] - this.dragSpecs.startPoint[0] :
35766 this.dragSpecs.startPoint[0] - endPoint[0]
35769 newSize = this.dragSpecs.startSize +
35770 (this.placement == Roo.bootstrap.SplitBar.TOP ?
35771 endPoint[1] - this.dragSpecs.startPoint[1] :
35772 this.dragSpecs.startPoint[1] - endPoint[1]
35775 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
35776 if(newSize != this.dragSpecs.startSize){
35777 if(this.fireEvent('beforeapply', this, newSize) !== false){
35778 this.adapter.setElementSize(this, newSize);
35779 this.fireEvent("moved", this, newSize);
35780 this.fireEvent("resize", this, newSize);
35786 * Get the adapter this SplitBar uses
35787 * @return The adapter object
35789 getAdapter : function(){
35790 return this.adapter;
35794 * Set the adapter this SplitBar uses
35795 * @param {Object} adapter A SplitBar adapter object
35797 setAdapter : function(adapter){
35798 this.adapter = adapter;
35799 this.adapter.init(this);
35803 * Gets the minimum size for the resizing element
35804 * @return {Number} The minimum size
35806 getMinimumSize : function(){
35807 return this.minSize;
35811 * Sets the minimum size for the resizing element
35812 * @param {Number} minSize The minimum size
35814 setMinimumSize : function(minSize){
35815 this.minSize = minSize;
35819 * Gets the maximum size for the resizing element
35820 * @return {Number} The maximum size
35822 getMaximumSize : function(){
35823 return this.maxSize;
35827 * Sets the maximum size for the resizing element
35828 * @param {Number} maxSize The maximum size
35830 setMaximumSize : function(maxSize){
35831 this.maxSize = maxSize;
35835 * Sets the initialize size for the resizing element
35836 * @param {Number} size The initial size
35838 setCurrentSize : function(size){
35839 var oldAnimate = this.animate;
35840 this.animate = false;
35841 this.adapter.setElementSize(this, size);
35842 this.animate = oldAnimate;
35846 * Destroy this splitbar.
35847 * @param {Boolean} removeEl True to remove the element
35849 destroy : function(removeEl){
35851 this.shim.remove();
35854 this.proxy.parentNode.removeChild(this.proxy);
35862 * @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.
35864 Roo.bootstrap.SplitBar.createProxy = function(dir){
35865 var proxy = new Roo.Element(document.createElement("div"));
35866 proxy.unselectable();
35867 var cls = 'roo-splitbar-proxy';
35868 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
35869 document.body.appendChild(proxy.dom);
35874 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
35875 * Default Adapter. It assumes the splitter and resizing element are not positioned
35876 * elements and only gets/sets the width of the element. Generally used for table based layouts.
35878 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
35881 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
35882 // do nothing for now
35883 init : function(s){
35887 * Called before drag operations to get the current size of the resizing element.
35888 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
35890 getElementSize : function(s){
35891 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35892 return s.resizingEl.getWidth();
35894 return s.resizingEl.getHeight();
35899 * Called after drag operations to set the size of the resizing element.
35900 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
35901 * @param {Number} newSize The new size to set
35902 * @param {Function} onComplete A function to be invoked when resizing is complete
35904 setElementSize : function(s, newSize, onComplete){
35905 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
35907 s.resizingEl.setWidth(newSize);
35909 onComplete(s, newSize);
35912 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
35917 s.resizingEl.setHeight(newSize);
35919 onComplete(s, newSize);
35922 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
35929 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
35930 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
35931 * Adapter that moves the splitter element to align with the resized sizing element.
35932 * Used with an absolute positioned SplitBar.
35933 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
35934 * document.body, make sure you assign an id to the body element.
35936 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
35937 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
35938 this.container = Roo.get(container);
35941 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
35942 init : function(s){
35943 this.basic.init(s);
35946 getElementSize : function(s){
35947 return this.basic.getElementSize(s);
35950 setElementSize : function(s, newSize, onComplete){
35951 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
35954 moveSplitter : function(s){
35955 var yes = Roo.bootstrap.SplitBar;
35956 switch(s.placement){
35958 s.el.setX(s.resizingEl.getRight());
35961 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
35964 s.el.setY(s.resizingEl.getBottom());
35967 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
35974 * Orientation constant - Create a vertical SplitBar
35978 Roo.bootstrap.SplitBar.VERTICAL = 1;
35981 * Orientation constant - Create a horizontal SplitBar
35985 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
35988 * Placement constant - The resizing element is to the left of the splitter element
35992 Roo.bootstrap.SplitBar.LEFT = 1;
35995 * Placement constant - The resizing element is to the right of the splitter element
35999 Roo.bootstrap.SplitBar.RIGHT = 2;
36002 * Placement constant - The resizing element is positioned above the splitter element
36006 Roo.bootstrap.SplitBar.TOP = 3;
36009 * Placement constant - The resizing element is positioned under splitter element
36013 Roo.bootstrap.SplitBar.BOTTOM = 4;
36014 Roo.namespace("Roo.bootstrap.layout");/*
36016 * Ext JS Library 1.1.1
36017 * Copyright(c) 2006-2007, Ext JS, LLC.
36019 * Originally Released Under LGPL - original licence link has changed is not relivant.
36022 * <script type="text/javascript">
36026 * @class Roo.bootstrap.layout.Manager
36027 * @extends Roo.bootstrap.Component
36028 * Base class for layout managers.
36030 Roo.bootstrap.layout.Manager = function(config)
36032 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
36038 /** false to disable window resize monitoring @type Boolean */
36039 this.monitorWindowResize = true;
36044 * Fires when a layout is performed.
36045 * @param {Roo.LayoutManager} this
36049 * @event regionresized
36050 * Fires when the user resizes a region.
36051 * @param {Roo.LayoutRegion} region The resized region
36052 * @param {Number} newSize The new size (width for east/west, height for north/south)
36054 "regionresized" : true,
36056 * @event regioncollapsed
36057 * Fires when a region is collapsed.
36058 * @param {Roo.LayoutRegion} region The collapsed region
36060 "regioncollapsed" : true,
36062 * @event regionexpanded
36063 * Fires when a region is expanded.
36064 * @param {Roo.LayoutRegion} region The expanded region
36066 "regionexpanded" : true
36068 this.updating = false;
36071 this.el = Roo.get(config.el);
36077 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
36082 monitorWindowResize : true,
36088 onRender : function(ct, position)
36091 this.el = Roo.get(ct);
36094 //this.fireEvent('render',this);
36098 initEvents: function()
36102 // ie scrollbar fix
36103 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
36104 document.body.scroll = "no";
36105 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
36106 this.el.position('relative');
36108 this.id = this.el.id;
36109 this.el.addClass("roo-layout-container");
36110 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
36111 if(this.el.dom != document.body ) {
36112 this.el.on('resize', this.layout,this);
36113 this.el.on('show', this.layout,this);
36119 * Returns true if this layout is currently being updated
36120 * @return {Boolean}
36122 isUpdating : function(){
36123 return this.updating;
36127 * Suspend the LayoutManager from doing auto-layouts while
36128 * making multiple add or remove calls
36130 beginUpdate : function(){
36131 this.updating = true;
36135 * Restore auto-layouts and optionally disable the manager from performing a layout
36136 * @param {Boolean} noLayout true to disable a layout update
36138 endUpdate : function(noLayout){
36139 this.updating = false;
36145 layout: function(){
36149 onRegionResized : function(region, newSize){
36150 this.fireEvent("regionresized", region, newSize);
36154 onRegionCollapsed : function(region){
36155 this.fireEvent("regioncollapsed", region);
36158 onRegionExpanded : function(region){
36159 this.fireEvent("regionexpanded", region);
36163 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
36164 * performs box-model adjustments.
36165 * @return {Object} The size as an object {width: (the width), height: (the height)}
36167 getViewSize : function()
36170 if(this.el.dom != document.body){
36171 size = this.el.getSize();
36173 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
36175 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
36176 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36181 * Returns the Element this layout is bound to.
36182 * @return {Roo.Element}
36184 getEl : function(){
36189 * Returns the specified region.
36190 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
36191 * @return {Roo.LayoutRegion}
36193 getRegion : function(target){
36194 return this.regions[target.toLowerCase()];
36197 onWindowResize : function(){
36198 if(this.monitorWindowResize){
36205 * Ext JS Library 1.1.1
36206 * Copyright(c) 2006-2007, Ext JS, LLC.
36208 * Originally Released Under LGPL - original licence link has changed is not relivant.
36211 * <script type="text/javascript">
36214 * @class Roo.bootstrap.layout.Border
36215 * @extends Roo.bootstrap.layout.Manager
36216 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
36217 * please see: examples/bootstrap/nested.html<br><br>
36219 <b>The container the layout is rendered into can be either the body element or any other element.
36220 If it is not the body element, the container needs to either be an absolute positioned element,
36221 or you will need to add "position:relative" to the css of the container. You will also need to specify
36222 the container size if it is not the body element.</b>
36225 * Create a new Border
36226 * @param {Object} config Configuration options
36228 Roo.bootstrap.layout.Border = function(config){
36229 config = config || {};
36230 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
36234 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
36235 if(config[region]){
36236 config[region].region = region;
36237 this.addRegion(config[region]);
36243 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
36245 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
36247 parent : false, // this might point to a 'nest' or a ???
36250 * Creates and adds a new region if it doesn't already exist.
36251 * @param {String} target The target region key (north, south, east, west or center).
36252 * @param {Object} config The regions config object
36253 * @return {BorderLayoutRegion} The new region
36255 addRegion : function(config)
36257 if(!this.regions[config.region]){
36258 var r = this.factory(config);
36259 this.bindRegion(r);
36261 return this.regions[config.region];
36265 bindRegion : function(r){
36266 this.regions[r.config.region] = r;
36268 r.on("visibilitychange", this.layout, this);
36269 r.on("paneladded", this.layout, this);
36270 r.on("panelremoved", this.layout, this);
36271 r.on("invalidated", this.layout, this);
36272 r.on("resized", this.onRegionResized, this);
36273 r.on("collapsed", this.onRegionCollapsed, this);
36274 r.on("expanded", this.onRegionExpanded, this);
36278 * Performs a layout update.
36280 layout : function()
36282 if(this.updating) {
36286 // render all the rebions if they have not been done alreayd?
36287 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
36288 if(this.regions[region] && !this.regions[region].bodyEl){
36289 this.regions[region].onRender(this.el)
36293 var size = this.getViewSize();
36294 var w = size.width;
36295 var h = size.height;
36300 //var x = 0, y = 0;
36302 var rs = this.regions;
36303 var north = rs["north"];
36304 var south = rs["south"];
36305 var west = rs["west"];
36306 var east = rs["east"];
36307 var center = rs["center"];
36308 //if(this.hideOnLayout){ // not supported anymore
36309 //c.el.setStyle("display", "none");
36311 if(north && north.isVisible()){
36312 var b = north.getBox();
36313 var m = north.getMargins();
36314 b.width = w - (m.left+m.right);
36317 centerY = b.height + b.y + m.bottom;
36318 centerH -= centerY;
36319 north.updateBox(this.safeBox(b));
36321 if(south && south.isVisible()){
36322 var b = south.getBox();
36323 var m = south.getMargins();
36324 b.width = w - (m.left+m.right);
36326 var totalHeight = (b.height + m.top + m.bottom);
36327 b.y = h - totalHeight + m.top;
36328 centerH -= totalHeight;
36329 south.updateBox(this.safeBox(b));
36331 if(west && west.isVisible()){
36332 var b = west.getBox();
36333 var m = west.getMargins();
36334 b.height = centerH - (m.top+m.bottom);
36336 b.y = centerY + m.top;
36337 var totalWidth = (b.width + m.left + m.right);
36338 centerX += totalWidth;
36339 centerW -= totalWidth;
36340 west.updateBox(this.safeBox(b));
36342 if(east && east.isVisible()){
36343 var b = east.getBox();
36344 var m = east.getMargins();
36345 b.height = centerH - (m.top+m.bottom);
36346 var totalWidth = (b.width + m.left + m.right);
36347 b.x = w - totalWidth + m.left;
36348 b.y = centerY + m.top;
36349 centerW -= totalWidth;
36350 east.updateBox(this.safeBox(b));
36353 var m = center.getMargins();
36355 x: centerX + m.left,
36356 y: centerY + m.top,
36357 width: centerW - (m.left+m.right),
36358 height: centerH - (m.top+m.bottom)
36360 //if(this.hideOnLayout){
36361 //center.el.setStyle("display", "block");
36363 center.updateBox(this.safeBox(centerBox));
36366 this.fireEvent("layout", this);
36370 safeBox : function(box){
36371 box.width = Math.max(0, box.width);
36372 box.height = Math.max(0, box.height);
36377 * Adds a ContentPanel (or subclass) to this layout.
36378 * @param {String} target The target region key (north, south, east, west or center).
36379 * @param {Roo.ContentPanel} panel The panel to add
36380 * @return {Roo.ContentPanel} The added panel
36382 add : function(target, panel){
36384 target = target.toLowerCase();
36385 return this.regions[target].add(panel);
36389 * Remove a ContentPanel (or subclass) to this layout.
36390 * @param {String} target The target region key (north, south, east, west or center).
36391 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
36392 * @return {Roo.ContentPanel} The removed panel
36394 remove : function(target, panel){
36395 target = target.toLowerCase();
36396 return this.regions[target].remove(panel);
36400 * Searches all regions for a panel with the specified id
36401 * @param {String} panelId
36402 * @return {Roo.ContentPanel} The panel or null if it wasn't found
36404 findPanel : function(panelId){
36405 var rs = this.regions;
36406 for(var target in rs){
36407 if(typeof rs[target] != "function"){
36408 var p = rs[target].getPanel(panelId);
36418 * Searches all regions for a panel with the specified id and activates (shows) it.
36419 * @param {String/ContentPanel} panelId The panels id or the panel itself
36420 * @return {Roo.ContentPanel} The shown panel or null
36422 showPanel : function(panelId) {
36423 var rs = this.regions;
36424 for(var target in rs){
36425 var r = rs[target];
36426 if(typeof r != "function"){
36427 if(r.hasPanel(panelId)){
36428 return r.showPanel(panelId);
36436 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
36437 * @param {Roo.state.Provider} provider (optional) An alternate state provider
36440 restoreState : function(provider){
36442 provider = Roo.state.Manager;
36444 var sm = new Roo.LayoutStateManager();
36445 sm.init(this, provider);
36451 * Adds a xtype elements to the layout.
36455 xtype : 'ContentPanel',
36462 xtype : 'NestedLayoutPanel',
36468 items : [ ... list of content panels or nested layout panels.. ]
36472 * @param {Object} cfg Xtype definition of item to add.
36474 addxtype : function(cfg)
36476 // basically accepts a pannel...
36477 // can accept a layout region..!?!?
36478 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
36481 // theory? children can only be panels??
36483 //if (!cfg.xtype.match(/Panel$/)) {
36488 if (typeof(cfg.region) == 'undefined') {
36489 Roo.log("Failed to add Panel, region was not set");
36493 var region = cfg.region;
36499 xitems = cfg.items;
36504 if ( region == 'center') {
36505 Roo.log("Center: " + cfg.title);
36511 case 'Content': // ContentPanel (el, cfg)
36512 case 'Scroll': // ContentPanel (el, cfg)
36514 cfg.autoCreate = cfg.autoCreate || true;
36515 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36517 // var el = this.el.createChild();
36518 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
36521 this.add(region, ret);
36525 case 'TreePanel': // our new panel!
36526 cfg.el = this.el.createChild();
36527 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
36528 this.add(region, ret);
36533 // create a new Layout (which is a Border Layout...
36535 var clayout = cfg.layout;
36536 clayout.el = this.el.createChild();
36537 clayout.items = clayout.items || [];
36541 // replace this exitems with the clayout ones..
36542 xitems = clayout.items;
36544 // force background off if it's in center...
36545 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
36546 cfg.background = false;
36548 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
36551 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36552 //console.log('adding nested layout panel ' + cfg.toSource());
36553 this.add(region, ret);
36554 nb = {}; /// find first...
36559 // needs grid and region
36561 //var el = this.getRegion(region).el.createChild();
36563 *var el = this.el.createChild();
36564 // create the grid first...
36565 cfg.grid.container = el;
36566 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
36569 if (region == 'center' && this.active ) {
36570 cfg.background = false;
36573 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
36575 this.add(region, ret);
36577 if (cfg.background) {
36578 // render grid on panel activation (if panel background)
36579 ret.on('activate', function(gp) {
36580 if (!gp.grid.rendered) {
36581 // gp.grid.render(el);
36585 // cfg.grid.render(el);
36591 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
36592 // it was the old xcomponent building that caused this before.
36593 // espeically if border is the top element in the tree.
36603 if (typeof(Roo[cfg.xtype]) != 'undefined') {
36605 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
36606 this.add(region, ret);
36610 throw "Can not add '" + cfg.xtype + "' to Border";
36616 this.beginUpdate();
36620 Roo.each(xitems, function(i) {
36621 region = nb && i.region ? i.region : false;
36623 var add = ret.addxtype(i);
36626 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
36627 if (!i.background) {
36628 abn[region] = nb[region] ;
36635 // make the last non-background panel active..
36636 //if (nb) { Roo.log(abn); }
36639 for(var r in abn) {
36640 region = this.getRegion(r);
36642 // tried using nb[r], but it does not work..
36644 region.showPanel(abn[r]);
36655 factory : function(cfg)
36658 var validRegions = Roo.bootstrap.layout.Border.regions;
36660 var target = cfg.region;
36663 var r = Roo.bootstrap.layout;
36667 return new r.North(cfg);
36669 return new r.South(cfg);
36671 return new r.East(cfg);
36673 return new r.West(cfg);
36675 return new r.Center(cfg);
36677 throw 'Layout region "'+target+'" not supported.';
36684 * Ext JS Library 1.1.1
36685 * Copyright(c) 2006-2007, Ext JS, LLC.
36687 * Originally Released Under LGPL - original licence link has changed is not relivant.
36690 * <script type="text/javascript">
36694 * @class Roo.bootstrap.layout.Basic
36695 * @extends Roo.util.Observable
36696 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
36697 * and does not have a titlebar, tabs or any other features. All it does is size and position
36698 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
36699 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36700 * @cfg {string} region the region that it inhabits..
36701 * @cfg {bool} skipConfig skip config?
36705 Roo.bootstrap.layout.Basic = function(config){
36707 this.mgr = config.mgr;
36709 this.position = config.region;
36711 var skipConfig = config.skipConfig;
36715 * @scope Roo.BasicLayoutRegion
36719 * @event beforeremove
36720 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
36721 * @param {Roo.LayoutRegion} this
36722 * @param {Roo.ContentPanel} panel The panel
36723 * @param {Object} e The cancel event object
36725 "beforeremove" : true,
36727 * @event invalidated
36728 * Fires when the layout for this region is changed.
36729 * @param {Roo.LayoutRegion} this
36731 "invalidated" : true,
36733 * @event visibilitychange
36734 * Fires when this region is shown or hidden
36735 * @param {Roo.LayoutRegion} this
36736 * @param {Boolean} visibility true or false
36738 "visibilitychange" : true,
36740 * @event paneladded
36741 * Fires when a panel is added.
36742 * @param {Roo.LayoutRegion} this
36743 * @param {Roo.ContentPanel} panel The panel
36745 "paneladded" : true,
36747 * @event panelremoved
36748 * Fires when a panel is removed.
36749 * @param {Roo.LayoutRegion} this
36750 * @param {Roo.ContentPanel} panel The panel
36752 "panelremoved" : true,
36754 * @event beforecollapse
36755 * Fires when this region before collapse.
36756 * @param {Roo.LayoutRegion} this
36758 "beforecollapse" : true,
36761 * Fires when this region is collapsed.
36762 * @param {Roo.LayoutRegion} this
36764 "collapsed" : true,
36767 * Fires when this region is expanded.
36768 * @param {Roo.LayoutRegion} this
36773 * Fires when this region is slid into view.
36774 * @param {Roo.LayoutRegion} this
36776 "slideshow" : true,
36779 * Fires when this region slides out of view.
36780 * @param {Roo.LayoutRegion} this
36782 "slidehide" : true,
36784 * @event panelactivated
36785 * Fires when a panel is activated.
36786 * @param {Roo.LayoutRegion} this
36787 * @param {Roo.ContentPanel} panel The activated panel
36789 "panelactivated" : true,
36792 * Fires when the user resizes this region.
36793 * @param {Roo.LayoutRegion} this
36794 * @param {Number} newSize The new size (width for east/west, height for north/south)
36798 /** A collection of panels in this region. @type Roo.util.MixedCollection */
36799 this.panels = new Roo.util.MixedCollection();
36800 this.panels.getKey = this.getPanelId.createDelegate(this);
36802 this.activePanel = null;
36803 // ensure listeners are added...
36805 if (config.listeners || config.events) {
36806 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
36807 listeners : config.listeners || {},
36808 events : config.events || {}
36812 if(skipConfig !== true){
36813 this.applyConfig(config);
36817 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
36819 getPanelId : function(p){
36823 applyConfig : function(config){
36824 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36825 this.config = config;
36830 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
36831 * the width, for horizontal (north, south) the height.
36832 * @param {Number} newSize The new width or height
36834 resizeTo : function(newSize){
36835 var el = this.el ? this.el :
36836 (this.activePanel ? this.activePanel.getEl() : null);
36838 switch(this.position){
36841 el.setWidth(newSize);
36842 this.fireEvent("resized", this, newSize);
36846 el.setHeight(newSize);
36847 this.fireEvent("resized", this, newSize);
36853 getBox : function(){
36854 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
36857 getMargins : function(){
36858 return this.margins;
36861 updateBox : function(box){
36863 var el = this.activePanel.getEl();
36864 el.dom.style.left = box.x + "px";
36865 el.dom.style.top = box.y + "px";
36866 this.activePanel.setSize(box.width, box.height);
36870 * Returns the container element for this region.
36871 * @return {Roo.Element}
36873 getEl : function(){
36874 return this.activePanel;
36878 * Returns true if this region is currently visible.
36879 * @return {Boolean}
36881 isVisible : function(){
36882 return this.activePanel ? true : false;
36885 setActivePanel : function(panel){
36886 panel = this.getPanel(panel);
36887 if(this.activePanel && this.activePanel != panel){
36888 this.activePanel.setActiveState(false);
36889 this.activePanel.getEl().setLeftTop(-10000,-10000);
36891 this.activePanel = panel;
36892 panel.setActiveState(true);
36894 panel.setSize(this.box.width, this.box.height);
36896 this.fireEvent("panelactivated", this, panel);
36897 this.fireEvent("invalidated");
36901 * Show the specified panel.
36902 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
36903 * @return {Roo.ContentPanel} The shown panel or null
36905 showPanel : function(panel){
36906 panel = this.getPanel(panel);
36908 this.setActivePanel(panel);
36914 * Get the active panel for this region.
36915 * @return {Roo.ContentPanel} The active panel or null
36917 getActivePanel : function(){
36918 return this.activePanel;
36922 * Add the passed ContentPanel(s)
36923 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36924 * @return {Roo.ContentPanel} The panel added (if only one was added)
36926 add : function(panel){
36927 if(arguments.length > 1){
36928 for(var i = 0, len = arguments.length; i < len; i++) {
36929 this.add(arguments[i]);
36933 if(this.hasPanel(panel)){
36934 this.showPanel(panel);
36937 var el = panel.getEl();
36938 if(el.dom.parentNode != this.mgr.el.dom){
36939 this.mgr.el.dom.appendChild(el.dom);
36941 if(panel.setRegion){
36942 panel.setRegion(this);
36944 this.panels.add(panel);
36945 el.setStyle("position", "absolute");
36946 if(!panel.background){
36947 this.setActivePanel(panel);
36948 if(this.config.initialSize && this.panels.getCount()==1){
36949 this.resizeTo(this.config.initialSize);
36952 this.fireEvent("paneladded", this, panel);
36957 * Returns true if the panel is in this region.
36958 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36959 * @return {Boolean}
36961 hasPanel : function(panel){
36962 if(typeof panel == "object"){ // must be panel obj
36963 panel = panel.getId();
36965 return this.getPanel(panel) ? true : false;
36969 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36970 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36971 * @param {Boolean} preservePanel Overrides the config preservePanel option
36972 * @return {Roo.ContentPanel} The panel that was removed
36974 remove : function(panel, preservePanel){
36975 panel = this.getPanel(panel);
36980 this.fireEvent("beforeremove", this, panel, e);
36981 if(e.cancel === true){
36984 var panelId = panel.getId();
36985 this.panels.removeKey(panelId);
36990 * Returns the panel specified or null if it's not in this region.
36991 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36992 * @return {Roo.ContentPanel}
36994 getPanel : function(id){
36995 if(typeof id == "object"){ // must be panel obj
36998 return this.panels.get(id);
37002 * Returns this regions position (north/south/east/west/center).
37005 getPosition: function(){
37006 return this.position;
37010 * Ext JS Library 1.1.1
37011 * Copyright(c) 2006-2007, Ext JS, LLC.
37013 * Originally Released Under LGPL - original licence link has changed is not relivant.
37016 * <script type="text/javascript">
37020 * @class Roo.bootstrap.layout.Region
37021 * @extends Roo.bootstrap.layout.Basic
37022 * This class represents a region in a layout manager.
37024 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
37025 * @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})
37026 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
37027 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
37028 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
37029 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
37030 * @cfg {String} title The title for the region (overrides panel titles)
37031 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
37032 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
37033 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
37034 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
37035 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
37036 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
37037 * the space available, similar to FireFox 1.5 tabs (defaults to false)
37038 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
37039 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
37040 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
37042 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
37043 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
37044 * @cfg {Boolean} disableTabTips True to disable tab tooltips
37045 * @cfg {Number} width For East/West panels
37046 * @cfg {Number} height For North/South panels
37047 * @cfg {Boolean} split To show the splitter
37048 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
37050 * @cfg {string} cls Extra CSS classes to add to region
37052 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37053 * @cfg {string} region the region that it inhabits..
37056 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
37057 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
37059 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
37060 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
37061 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
37063 Roo.bootstrap.layout.Region = function(config)
37065 this.applyConfig(config);
37067 var mgr = config.mgr;
37068 var pos = config.region;
37069 config.skipConfig = true;
37070 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
37073 this.onRender(mgr.el);
37076 this.visible = true;
37077 this.collapsed = false;
37078 this.unrendered_panels = [];
37081 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
37083 position: '', // set by wrapper (eg. north/south etc..)
37084 unrendered_panels : null, // unrendered panels.
37086 tabPosition : false,
37088 mgr: false, // points to 'Border'
37091 createBody : function(){
37092 /** This region's body element
37093 * @type Roo.Element */
37094 this.bodyEl = this.el.createChild({
37096 cls: "roo-layout-panel-body tab-content" // bootstrap added...
37100 onRender: function(ctr, pos)
37102 var dh = Roo.DomHelper;
37103 /** This region's container element
37104 * @type Roo.Element */
37105 this.el = dh.append(ctr.dom, {
37107 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
37109 /** This region's title element
37110 * @type Roo.Element */
37112 this.titleEl = dh.append(this.el.dom, {
37114 unselectable: "on",
37115 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
37117 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
37118 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
37122 this.titleEl.enableDisplayMode();
37123 /** This region's title text element
37124 * @type HTMLElement */
37125 this.titleTextEl = this.titleEl.dom.firstChild;
37126 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
37128 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
37129 this.closeBtn.enableDisplayMode();
37130 this.closeBtn.on("click", this.closeClicked, this);
37131 this.closeBtn.hide();
37133 this.createBody(this.config);
37134 if(this.config.hideWhenEmpty){
37136 this.on("paneladded", this.validateVisibility, this);
37137 this.on("panelremoved", this.validateVisibility, this);
37139 if(this.autoScroll){
37140 this.bodyEl.setStyle("overflow", "auto");
37142 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
37144 //if(c.titlebar !== false){
37145 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
37146 this.titleEl.hide();
37148 this.titleEl.show();
37149 if(this.config.title){
37150 this.titleTextEl.innerHTML = this.config.title;
37154 if(this.config.collapsed){
37155 this.collapse(true);
37157 if(this.config.hidden){
37161 if (this.unrendered_panels && this.unrendered_panels.length) {
37162 for (var i =0;i< this.unrendered_panels.length; i++) {
37163 this.add(this.unrendered_panels[i]);
37165 this.unrendered_panels = null;
37171 applyConfig : function(c)
37174 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
37175 var dh = Roo.DomHelper;
37176 if(c.titlebar !== false){
37177 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
37178 this.collapseBtn.on("click", this.collapse, this);
37179 this.collapseBtn.enableDisplayMode();
37181 if(c.showPin === true || this.showPin){
37182 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
37183 this.stickBtn.enableDisplayMode();
37184 this.stickBtn.on("click", this.expand, this);
37185 this.stickBtn.hide();
37190 /** This region's collapsed element
37191 * @type Roo.Element */
37194 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
37195 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
37198 if(c.floatable !== false){
37199 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
37200 this.collapsedEl.on("click", this.collapseClick, this);
37203 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
37204 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
37205 id: "message", unselectable: "on", style:{"float":"left"}});
37206 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
37208 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
37209 this.expandBtn.on("click", this.expand, this);
37213 if(this.collapseBtn){
37214 this.collapseBtn.setVisible(c.collapsible == true);
37217 this.cmargins = c.cmargins || this.cmargins ||
37218 (this.position == "west" || this.position == "east" ?
37219 {top: 0, left: 2, right:2, bottom: 0} :
37220 {top: 2, left: 0, right:0, bottom: 2});
37222 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
37225 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
37227 this.autoScroll = c.autoScroll || false;
37232 this.duration = c.duration || .30;
37233 this.slideDuration = c.slideDuration || .45;
37238 * Returns true if this region is currently visible.
37239 * @return {Boolean}
37241 isVisible : function(){
37242 return this.visible;
37246 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
37247 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
37249 //setCollapsedTitle : function(title){
37250 // title = title || " ";
37251 // if(this.collapsedTitleTextEl){
37252 // this.collapsedTitleTextEl.innerHTML = title;
37256 getBox : function(){
37258 // if(!this.collapsed){
37259 b = this.el.getBox(false, true);
37261 // b = this.collapsedEl.getBox(false, true);
37266 getMargins : function(){
37267 return this.margins;
37268 //return this.collapsed ? this.cmargins : this.margins;
37271 highlight : function(){
37272 this.el.addClass("x-layout-panel-dragover");
37275 unhighlight : function(){
37276 this.el.removeClass("x-layout-panel-dragover");
37279 updateBox : function(box)
37281 if (!this.bodyEl) {
37282 return; // not rendered yet..
37286 if(!this.collapsed){
37287 this.el.dom.style.left = box.x + "px";
37288 this.el.dom.style.top = box.y + "px";
37289 this.updateBody(box.width, box.height);
37291 this.collapsedEl.dom.style.left = box.x + "px";
37292 this.collapsedEl.dom.style.top = box.y + "px";
37293 this.collapsedEl.setSize(box.width, box.height);
37296 this.tabs.autoSizeTabs();
37300 updateBody : function(w, h)
37303 this.el.setWidth(w);
37304 w -= this.el.getBorderWidth("rl");
37305 if(this.config.adjustments){
37306 w += this.config.adjustments[0];
37309 if(h !== null && h > 0){
37310 this.el.setHeight(h);
37311 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
37312 h -= this.el.getBorderWidth("tb");
37313 if(this.config.adjustments){
37314 h += this.config.adjustments[1];
37316 this.bodyEl.setHeight(h);
37318 h = this.tabs.syncHeight(h);
37321 if(this.panelSize){
37322 w = w !== null ? w : this.panelSize.width;
37323 h = h !== null ? h : this.panelSize.height;
37325 if(this.activePanel){
37326 var el = this.activePanel.getEl();
37327 w = w !== null ? w : el.getWidth();
37328 h = h !== null ? h : el.getHeight();
37329 this.panelSize = {width: w, height: h};
37330 this.activePanel.setSize(w, h);
37332 if(Roo.isIE && this.tabs){
37333 this.tabs.el.repaint();
37338 * Returns the container element for this region.
37339 * @return {Roo.Element}
37341 getEl : function(){
37346 * Hides this region.
37349 //if(!this.collapsed){
37350 this.el.dom.style.left = "-2000px";
37353 // this.collapsedEl.dom.style.left = "-2000px";
37354 // this.collapsedEl.hide();
37356 this.visible = false;
37357 this.fireEvent("visibilitychange", this, false);
37361 * Shows this region if it was previously hidden.
37364 //if(!this.collapsed){
37367 // this.collapsedEl.show();
37369 this.visible = true;
37370 this.fireEvent("visibilitychange", this, true);
37373 closeClicked : function(){
37374 if(this.activePanel){
37375 this.remove(this.activePanel);
37379 collapseClick : function(e){
37381 e.stopPropagation();
37384 e.stopPropagation();
37390 * Collapses this region.
37391 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
37394 collapse : function(skipAnim, skipCheck = false){
37395 if(this.collapsed) {
37399 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
37401 this.collapsed = true;
37403 this.split.el.hide();
37405 if(this.config.animate && skipAnim !== true){
37406 this.fireEvent("invalidated", this);
37407 this.animateCollapse();
37409 this.el.setLocation(-20000,-20000);
37411 this.collapsedEl.show();
37412 this.fireEvent("collapsed", this);
37413 this.fireEvent("invalidated", this);
37419 animateCollapse : function(){
37424 * Expands this region if it was previously collapsed.
37425 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
37426 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
37429 expand : function(e, skipAnim){
37431 e.stopPropagation();
37433 if(!this.collapsed || this.el.hasActiveFx()) {
37437 this.afterSlideIn();
37440 this.collapsed = false;
37441 if(this.config.animate && skipAnim !== true){
37442 this.animateExpand();
37446 this.split.el.show();
37448 this.collapsedEl.setLocation(-2000,-2000);
37449 this.collapsedEl.hide();
37450 this.fireEvent("invalidated", this);
37451 this.fireEvent("expanded", this);
37455 animateExpand : function(){
37459 initTabs : function()
37461 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
37463 var ts = new Roo.bootstrap.panel.Tabs({
37464 el: this.bodyEl.dom,
37466 tabPosition: this.tabPosition ? this.tabPosition : 'top',
37467 disableTooltips: this.config.disableTabTips,
37468 toolbar : this.config.toolbar
37471 if(this.config.hideTabs){
37472 ts.stripWrap.setDisplayed(false);
37475 ts.resizeTabs = this.config.resizeTabs === true;
37476 ts.minTabWidth = this.config.minTabWidth || 40;
37477 ts.maxTabWidth = this.config.maxTabWidth || 250;
37478 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
37479 ts.monitorResize = false;
37480 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
37481 ts.bodyEl.addClass('roo-layout-tabs-body');
37482 this.panels.each(this.initPanelAsTab, this);
37485 initPanelAsTab : function(panel){
37486 var ti = this.tabs.addTab(
37490 this.config.closeOnTab && panel.isClosable(),
37493 if(panel.tabTip !== undefined){
37494 ti.setTooltip(panel.tabTip);
37496 ti.on("activate", function(){
37497 this.setActivePanel(panel);
37500 if(this.config.closeOnTab){
37501 ti.on("beforeclose", function(t, e){
37503 this.remove(panel);
37507 panel.tabItem = ti;
37512 updatePanelTitle : function(panel, title)
37514 if(this.activePanel == panel){
37515 this.updateTitle(title);
37518 var ti = this.tabs.getTab(panel.getEl().id);
37520 if(panel.tabTip !== undefined){
37521 ti.setTooltip(panel.tabTip);
37526 updateTitle : function(title){
37527 if(this.titleTextEl && !this.config.title){
37528 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
37532 setActivePanel : function(panel)
37534 panel = this.getPanel(panel);
37535 if(this.activePanel && this.activePanel != panel){
37536 if(this.activePanel.setActiveState(false) === false){
37540 this.activePanel = panel;
37541 panel.setActiveState(true);
37542 if(this.panelSize){
37543 panel.setSize(this.panelSize.width, this.panelSize.height);
37546 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
37548 this.updateTitle(panel.getTitle());
37550 this.fireEvent("invalidated", this);
37552 this.fireEvent("panelactivated", this, panel);
37556 * Shows the specified panel.
37557 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
37558 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
37560 showPanel : function(panel)
37562 panel = this.getPanel(panel);
37565 var tab = this.tabs.getTab(panel.getEl().id);
37566 if(tab.isHidden()){
37567 this.tabs.unhideTab(tab.id);
37571 this.setActivePanel(panel);
37578 * Get the active panel for this region.
37579 * @return {Roo.ContentPanel} The active panel or null
37581 getActivePanel : function(){
37582 return this.activePanel;
37585 validateVisibility : function(){
37586 if(this.panels.getCount() < 1){
37587 this.updateTitle(" ");
37588 this.closeBtn.hide();
37591 if(!this.isVisible()){
37598 * Adds the passed ContentPanel(s) to this region.
37599 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
37600 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
37602 add : function(panel)
37604 if(arguments.length > 1){
37605 for(var i = 0, len = arguments.length; i < len; i++) {
37606 this.add(arguments[i]);
37611 // if we have not been rendered yet, then we can not really do much of this..
37612 if (!this.bodyEl) {
37613 this.unrendered_panels.push(panel);
37620 if(this.hasPanel(panel)){
37621 this.showPanel(panel);
37624 panel.setRegion(this);
37625 this.panels.add(panel);
37626 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
37627 // sinle panel - no tab...?? would it not be better to render it with the tabs,
37628 // and hide them... ???
37629 this.bodyEl.dom.appendChild(panel.getEl().dom);
37630 if(panel.background !== true){
37631 this.setActivePanel(panel);
37633 this.fireEvent("paneladded", this, panel);
37640 this.initPanelAsTab(panel);
37644 if(panel.background !== true){
37645 this.tabs.activate(panel.getEl().id);
37647 this.fireEvent("paneladded", this, panel);
37652 * Hides the tab for the specified panel.
37653 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37655 hidePanel : function(panel){
37656 if(this.tabs && (panel = this.getPanel(panel))){
37657 this.tabs.hideTab(panel.getEl().id);
37662 * Unhides the tab for a previously hidden panel.
37663 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37665 unhidePanel : function(panel){
37666 if(this.tabs && (panel = this.getPanel(panel))){
37667 this.tabs.unhideTab(panel.getEl().id);
37671 clearPanels : function(){
37672 while(this.panels.getCount() > 0){
37673 this.remove(this.panels.first());
37678 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
37679 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
37680 * @param {Boolean} preservePanel Overrides the config preservePanel option
37681 * @return {Roo.ContentPanel} The panel that was removed
37683 remove : function(panel, preservePanel)
37685 panel = this.getPanel(panel);
37690 this.fireEvent("beforeremove", this, panel, e);
37691 if(e.cancel === true){
37694 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
37695 var panelId = panel.getId();
37696 this.panels.removeKey(panelId);
37698 document.body.appendChild(panel.getEl().dom);
37701 this.tabs.removeTab(panel.getEl().id);
37702 }else if (!preservePanel){
37703 this.bodyEl.dom.removeChild(panel.getEl().dom);
37705 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
37706 var p = this.panels.first();
37707 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
37708 tempEl.appendChild(p.getEl().dom);
37709 this.bodyEl.update("");
37710 this.bodyEl.dom.appendChild(p.getEl().dom);
37712 this.updateTitle(p.getTitle());
37714 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
37715 this.setActivePanel(p);
37717 panel.setRegion(null);
37718 if(this.activePanel == panel){
37719 this.activePanel = null;
37721 if(this.config.autoDestroy !== false && preservePanel !== true){
37722 try{panel.destroy();}catch(e){}
37724 this.fireEvent("panelremoved", this, panel);
37729 * Returns the TabPanel component used by this region
37730 * @return {Roo.TabPanel}
37732 getTabs : function(){
37736 createTool : function(parentEl, className){
37737 var btn = Roo.DomHelper.append(parentEl, {
37739 cls: "x-layout-tools-button",
37742 cls: "roo-layout-tools-button-inner " + className,
37746 btn.addClassOnOver("roo-layout-tools-button-over");
37751 * Ext JS Library 1.1.1
37752 * Copyright(c) 2006-2007, Ext JS, LLC.
37754 * Originally Released Under LGPL - original licence link has changed is not relivant.
37757 * <script type="text/javascript">
37763 * @class Roo.SplitLayoutRegion
37764 * @extends Roo.LayoutRegion
37765 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
37767 Roo.bootstrap.layout.Split = function(config){
37768 this.cursor = config.cursor;
37769 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
37772 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
37774 splitTip : "Drag to resize.",
37775 collapsibleSplitTip : "Drag to resize. Double click to hide.",
37776 useSplitTips : false,
37778 applyConfig : function(config){
37779 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
37782 onRender : function(ctr,pos) {
37784 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
37785 if(!this.config.split){
37790 var splitEl = Roo.DomHelper.append(ctr.dom, {
37792 id: this.el.id + "-split",
37793 cls: "roo-layout-split roo-layout-split-"+this.position,
37796 /** The SplitBar for this region
37797 * @type Roo.SplitBar */
37798 // does not exist yet...
37799 Roo.log([this.position, this.orientation]);
37801 this.split = new Roo.bootstrap.SplitBar({
37802 dragElement : splitEl,
37803 resizingElement: this.el,
37804 orientation : this.orientation
37807 this.split.on("moved", this.onSplitMove, this);
37808 this.split.useShim = this.config.useShim === true;
37809 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
37810 if(this.useSplitTips){
37811 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
37813 //if(config.collapsible){
37814 // this.split.el.on("dblclick", this.collapse, this);
37817 if(typeof this.config.minSize != "undefined"){
37818 this.split.minSize = this.config.minSize;
37820 if(typeof this.config.maxSize != "undefined"){
37821 this.split.maxSize = this.config.maxSize;
37823 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
37824 this.hideSplitter();
37829 getHMaxSize : function(){
37830 var cmax = this.config.maxSize || 10000;
37831 var center = this.mgr.getRegion("center");
37832 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
37835 getVMaxSize : function(){
37836 var cmax = this.config.maxSize || 10000;
37837 var center = this.mgr.getRegion("center");
37838 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
37841 onSplitMove : function(split, newSize){
37842 this.fireEvent("resized", this, newSize);
37846 * Returns the {@link Roo.SplitBar} for this region.
37847 * @return {Roo.SplitBar}
37849 getSplitBar : function(){
37854 this.hideSplitter();
37855 Roo.bootstrap.layout.Split.superclass.hide.call(this);
37858 hideSplitter : function(){
37860 this.split.el.setLocation(-2000,-2000);
37861 this.split.el.hide();
37867 this.split.el.show();
37869 Roo.bootstrap.layout.Split.superclass.show.call(this);
37872 beforeSlide: function(){
37873 if(Roo.isGecko){// firefox overflow auto bug workaround
37874 this.bodyEl.clip();
37876 this.tabs.bodyEl.clip();
37878 if(this.activePanel){
37879 this.activePanel.getEl().clip();
37881 if(this.activePanel.beforeSlide){
37882 this.activePanel.beforeSlide();
37888 afterSlide : function(){
37889 if(Roo.isGecko){// firefox overflow auto bug workaround
37890 this.bodyEl.unclip();
37892 this.tabs.bodyEl.unclip();
37894 if(this.activePanel){
37895 this.activePanel.getEl().unclip();
37896 if(this.activePanel.afterSlide){
37897 this.activePanel.afterSlide();
37903 initAutoHide : function(){
37904 if(this.autoHide !== false){
37905 if(!this.autoHideHd){
37906 var st = new Roo.util.DelayedTask(this.slideIn, this);
37907 this.autoHideHd = {
37908 "mouseout": function(e){
37909 if(!e.within(this.el, true)){
37913 "mouseover" : function(e){
37919 this.el.on(this.autoHideHd);
37923 clearAutoHide : function(){
37924 if(this.autoHide !== false){
37925 this.el.un("mouseout", this.autoHideHd.mouseout);
37926 this.el.un("mouseover", this.autoHideHd.mouseover);
37930 clearMonitor : function(){
37931 Roo.get(document).un("click", this.slideInIf, this);
37934 // these names are backwards but not changed for compat
37935 slideOut : function(){
37936 if(this.isSlid || this.el.hasActiveFx()){
37939 this.isSlid = true;
37940 if(this.collapseBtn){
37941 this.collapseBtn.hide();
37943 this.closeBtnState = this.closeBtn.getStyle('display');
37944 this.closeBtn.hide();
37946 this.stickBtn.show();
37949 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
37950 this.beforeSlide();
37951 this.el.setStyle("z-index", 10001);
37952 this.el.slideIn(this.getSlideAnchor(), {
37953 callback: function(){
37955 this.initAutoHide();
37956 Roo.get(document).on("click", this.slideInIf, this);
37957 this.fireEvent("slideshow", this);
37964 afterSlideIn : function(){
37965 this.clearAutoHide();
37966 this.isSlid = false;
37967 this.clearMonitor();
37968 this.el.setStyle("z-index", "");
37969 if(this.collapseBtn){
37970 this.collapseBtn.show();
37972 this.closeBtn.setStyle('display', this.closeBtnState);
37974 this.stickBtn.hide();
37976 this.fireEvent("slidehide", this);
37979 slideIn : function(cb){
37980 if(!this.isSlid || this.el.hasActiveFx()){
37984 this.isSlid = false;
37985 this.beforeSlide();
37986 this.el.slideOut(this.getSlideAnchor(), {
37987 callback: function(){
37988 this.el.setLeftTop(-10000, -10000);
37990 this.afterSlideIn();
37998 slideInIf : function(e){
37999 if(!e.within(this.el)){
38004 animateCollapse : function(){
38005 this.beforeSlide();
38006 this.el.setStyle("z-index", 20000);
38007 var anchor = this.getSlideAnchor();
38008 this.el.slideOut(anchor, {
38009 callback : function(){
38010 this.el.setStyle("z-index", "");
38011 this.collapsedEl.slideIn(anchor, {duration:.3});
38013 this.el.setLocation(-10000,-10000);
38015 this.fireEvent("collapsed", this);
38022 animateExpand : function(){
38023 this.beforeSlide();
38024 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
38025 this.el.setStyle("z-index", 20000);
38026 this.collapsedEl.hide({
38029 this.el.slideIn(this.getSlideAnchor(), {
38030 callback : function(){
38031 this.el.setStyle("z-index", "");
38034 this.split.el.show();
38036 this.fireEvent("invalidated", this);
38037 this.fireEvent("expanded", this);
38065 getAnchor : function(){
38066 return this.anchors[this.position];
38069 getCollapseAnchor : function(){
38070 return this.canchors[this.position];
38073 getSlideAnchor : function(){
38074 return this.sanchors[this.position];
38077 getAlignAdj : function(){
38078 var cm = this.cmargins;
38079 switch(this.position){
38095 getExpandAdj : function(){
38096 var c = this.collapsedEl, cm = this.cmargins;
38097 switch(this.position){
38099 return [-(cm.right+c.getWidth()+cm.left), 0];
38102 return [cm.right+c.getWidth()+cm.left, 0];
38105 return [0, -(cm.top+cm.bottom+c.getHeight())];
38108 return [0, cm.top+cm.bottom+c.getHeight()];
38114 * Ext JS Library 1.1.1
38115 * Copyright(c) 2006-2007, Ext JS, LLC.
38117 * Originally Released Under LGPL - original licence link has changed is not relivant.
38120 * <script type="text/javascript">
38123 * These classes are private internal classes
38125 Roo.bootstrap.layout.Center = function(config){
38126 config.region = "center";
38127 Roo.bootstrap.layout.Region.call(this, config);
38128 this.visible = true;
38129 this.minWidth = config.minWidth || 20;
38130 this.minHeight = config.minHeight || 20;
38133 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
38135 // center panel can't be hidden
38139 // center panel can't be hidden
38142 getMinWidth: function(){
38143 return this.minWidth;
38146 getMinHeight: function(){
38147 return this.minHeight;
38161 Roo.bootstrap.layout.North = function(config)
38163 config.region = 'north';
38164 config.cursor = 'n-resize';
38166 Roo.bootstrap.layout.Split.call(this, config);
38170 this.split.placement = Roo.bootstrap.SplitBar.TOP;
38171 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38172 this.split.el.addClass("roo-layout-split-v");
38174 var size = config.initialSize || config.height;
38175 if(typeof size != "undefined"){
38176 this.el.setHeight(size);
38179 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
38181 orientation: Roo.bootstrap.SplitBar.VERTICAL,
38185 getBox : function(){
38186 if(this.collapsed){
38187 return this.collapsedEl.getBox();
38189 var box = this.el.getBox();
38191 box.height += this.split.el.getHeight();
38196 updateBox : function(box){
38197 if(this.split && !this.collapsed){
38198 box.height -= this.split.el.getHeight();
38199 this.split.el.setLeft(box.x);
38200 this.split.el.setTop(box.y+box.height);
38201 this.split.el.setWidth(box.width);
38203 if(this.collapsed){
38204 this.updateBody(box.width, null);
38206 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38214 Roo.bootstrap.layout.South = function(config){
38215 config.region = 'south';
38216 config.cursor = 's-resize';
38217 Roo.bootstrap.layout.Split.call(this, config);
38219 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
38220 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38221 this.split.el.addClass("roo-layout-split-v");
38223 var size = config.initialSize || config.height;
38224 if(typeof size != "undefined"){
38225 this.el.setHeight(size);
38229 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
38230 orientation: Roo.bootstrap.SplitBar.VERTICAL,
38231 getBox : function(){
38232 if(this.collapsed){
38233 return this.collapsedEl.getBox();
38235 var box = this.el.getBox();
38237 var sh = this.split.el.getHeight();
38244 updateBox : function(box){
38245 if(this.split && !this.collapsed){
38246 var sh = this.split.el.getHeight();
38249 this.split.el.setLeft(box.x);
38250 this.split.el.setTop(box.y-sh);
38251 this.split.el.setWidth(box.width);
38253 if(this.collapsed){
38254 this.updateBody(box.width, null);
38256 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38260 Roo.bootstrap.layout.East = function(config){
38261 config.region = "east";
38262 config.cursor = "e-resize";
38263 Roo.bootstrap.layout.Split.call(this, config);
38265 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
38266 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
38267 this.split.el.addClass("roo-layout-split-h");
38269 var size = config.initialSize || config.width;
38270 if(typeof size != "undefined"){
38271 this.el.setWidth(size);
38274 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
38275 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
38276 getBox : function(){
38277 if(this.collapsed){
38278 return this.collapsedEl.getBox();
38280 var box = this.el.getBox();
38282 var sw = this.split.el.getWidth();
38289 updateBox : function(box){
38290 if(this.split && !this.collapsed){
38291 var sw = this.split.el.getWidth();
38293 this.split.el.setLeft(box.x);
38294 this.split.el.setTop(box.y);
38295 this.split.el.setHeight(box.height);
38298 if(this.collapsed){
38299 this.updateBody(null, box.height);
38301 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38305 Roo.bootstrap.layout.West = function(config){
38306 config.region = "west";
38307 config.cursor = "w-resize";
38309 Roo.bootstrap.layout.Split.call(this, config);
38311 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
38312 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
38313 this.split.el.addClass("roo-layout-split-h");
38317 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
38318 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
38320 onRender: function(ctr, pos)
38322 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
38323 var size = this.config.initialSize || this.config.width;
38324 if(typeof size != "undefined"){
38325 this.el.setWidth(size);
38329 getBox : function(){
38330 if(this.collapsed){
38331 return this.collapsedEl.getBox();
38333 var box = this.el.getBox();
38335 box.width += this.split.el.getWidth();
38340 updateBox : function(box){
38341 if(this.split && !this.collapsed){
38342 var sw = this.split.el.getWidth();
38344 this.split.el.setLeft(box.x+box.width);
38345 this.split.el.setTop(box.y);
38346 this.split.el.setHeight(box.height);
38348 if(this.collapsed){
38349 this.updateBody(null, box.height);
38351 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38353 });Roo.namespace("Roo.bootstrap.panel");/*
38355 * Ext JS Library 1.1.1
38356 * Copyright(c) 2006-2007, Ext JS, LLC.
38358 * Originally Released Under LGPL - original licence link has changed is not relivant.
38361 * <script type="text/javascript">
38364 * @class Roo.ContentPanel
38365 * @extends Roo.util.Observable
38366 * A basic ContentPanel element.
38367 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
38368 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
38369 * @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
38370 * @cfg {Boolean} closable True if the panel can be closed/removed
38371 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
38372 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
38373 * @cfg {Toolbar} toolbar A toolbar for this panel
38374 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
38375 * @cfg {String} title The title for this panel
38376 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
38377 * @cfg {String} url Calls {@link #setUrl} with this value
38378 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
38379 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
38380 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
38381 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
38382 * @cfg {Boolean} badges render the badges
38385 * Create a new ContentPanel.
38386 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
38387 * @param {String/Object} config A string to set only the title or a config object
38388 * @param {String} content (optional) Set the HTML content for this panel
38389 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
38391 Roo.bootstrap.panel.Content = function( config){
38393 this.tpl = config.tpl || false;
38395 var el = config.el;
38396 var content = config.content;
38398 if(config.autoCreate){ // xtype is available if this is called from factory
38401 this.el = Roo.get(el);
38402 if(!this.el && config && config.autoCreate){
38403 if(typeof config.autoCreate == "object"){
38404 if(!config.autoCreate.id){
38405 config.autoCreate.id = config.id||el;
38407 this.el = Roo.DomHelper.append(document.body,
38408 config.autoCreate, true);
38410 var elcfg = { tag: "div",
38411 cls: "roo-layout-inactive-content",
38415 elcfg.html = config.html;
38419 this.el = Roo.DomHelper.append(document.body, elcfg , true);
38422 this.closable = false;
38423 this.loaded = false;
38424 this.active = false;
38427 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
38429 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
38431 this.wrapEl = this.el; //this.el.wrap();
38433 if (config.toolbar.items) {
38434 ti = config.toolbar.items ;
38435 delete config.toolbar.items ;
38439 this.toolbar.render(this.wrapEl, 'before');
38440 for(var i =0;i < ti.length;i++) {
38441 // Roo.log(['add child', items[i]]);
38442 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
38444 this.toolbar.items = nitems;
38445 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
38446 delete config.toolbar;
38450 // xtype created footer. - not sure if will work as we normally have to render first..
38451 if (this.footer && !this.footer.el && this.footer.xtype) {
38452 if (!this.wrapEl) {
38453 this.wrapEl = this.el.wrap();
38456 this.footer.container = this.wrapEl.createChild();
38458 this.footer = Roo.factory(this.footer, Roo);
38463 if(typeof config == "string"){
38464 this.title = config;
38466 Roo.apply(this, config);
38470 this.resizeEl = Roo.get(this.resizeEl, true);
38472 this.resizeEl = this.el;
38474 // handle view.xtype
38482 * Fires when this panel is activated.
38483 * @param {Roo.ContentPanel} this
38487 * @event deactivate
38488 * Fires when this panel is activated.
38489 * @param {Roo.ContentPanel} this
38491 "deactivate" : true,
38495 * Fires when this panel is resized if fitToFrame is true.
38496 * @param {Roo.ContentPanel} this
38497 * @param {Number} width The width after any component adjustments
38498 * @param {Number} height The height after any component adjustments
38504 * Fires when this tab is created
38505 * @param {Roo.ContentPanel} this
38516 if(this.autoScroll){
38517 this.resizeEl.setStyle("overflow", "auto");
38519 // fix randome scrolling
38520 //this.el.on('scroll', function() {
38521 // Roo.log('fix random scolling');
38522 // this.scrollTo('top',0);
38525 content = content || this.content;
38527 this.setContent(content);
38529 if(config && config.url){
38530 this.setUrl(this.url, this.params, this.loadOnce);
38535 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
38537 if (this.view && typeof(this.view.xtype) != 'undefined') {
38538 this.view.el = this.el.appendChild(document.createElement("div"));
38539 this.view = Roo.factory(this.view);
38540 this.view.render && this.view.render(false, '');
38544 this.fireEvent('render', this);
38547 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
38551 setRegion : function(region){
38552 this.region = region;
38553 this.setActiveClass(region && !this.background);
38557 setActiveClass: function(state)
38560 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
38561 this.el.setStyle('position','relative');
38563 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
38564 this.el.setStyle('position', 'absolute');
38569 * Returns the toolbar for this Panel if one was configured.
38570 * @return {Roo.Toolbar}
38572 getToolbar : function(){
38573 return this.toolbar;
38576 setActiveState : function(active)
38578 this.active = active;
38579 this.setActiveClass(active);
38581 if(this.fireEvent("deactivate", this) === false){
38586 this.fireEvent("activate", this);
38590 * Updates this panel's element
38591 * @param {String} content The new content
38592 * @param {Boolean} loadScripts (optional) true to look for and process scripts
38594 setContent : function(content, loadScripts){
38595 this.el.update(content, loadScripts);
38598 ignoreResize : function(w, h){
38599 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
38602 this.lastSize = {width: w, height: h};
38607 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
38608 * @return {Roo.UpdateManager} The UpdateManager
38610 getUpdateManager : function(){
38611 return this.el.getUpdateManager();
38614 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
38615 * @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:
38618 url: "your-url.php",
38619 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
38620 callback: yourFunction,
38621 scope: yourObject, //(optional scope)
38624 text: "Loading...",
38629 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
38630 * 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.
38631 * @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}
38632 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
38633 * @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.
38634 * @return {Roo.ContentPanel} this
38637 var um = this.el.getUpdateManager();
38638 um.update.apply(um, arguments);
38644 * 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.
38645 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
38646 * @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)
38647 * @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)
38648 * @return {Roo.UpdateManager} The UpdateManager
38650 setUrl : function(url, params, loadOnce){
38651 if(this.refreshDelegate){
38652 this.removeListener("activate", this.refreshDelegate);
38654 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38655 this.on("activate", this.refreshDelegate);
38656 return this.el.getUpdateManager();
38659 _handleRefresh : function(url, params, loadOnce){
38660 if(!loadOnce || !this.loaded){
38661 var updater = this.el.getUpdateManager();
38662 updater.update(url, params, this._setLoaded.createDelegate(this));
38666 _setLoaded : function(){
38667 this.loaded = true;
38671 * Returns this panel's id
38674 getId : function(){
38679 * Returns this panel's element - used by regiosn to add.
38680 * @return {Roo.Element}
38682 getEl : function(){
38683 return this.wrapEl || this.el;
38688 adjustForComponents : function(width, height)
38690 //Roo.log('adjustForComponents ');
38691 if(this.resizeEl != this.el){
38692 width -= this.el.getFrameWidth('lr');
38693 height -= this.el.getFrameWidth('tb');
38696 var te = this.toolbar.getEl();
38697 te.setWidth(width);
38698 height -= te.getHeight();
38701 var te = this.footer.getEl();
38702 te.setWidth(width);
38703 height -= te.getHeight();
38707 if(this.adjustments){
38708 width += this.adjustments[0];
38709 height += this.adjustments[1];
38711 return {"width": width, "height": height};
38714 setSize : function(width, height){
38715 if(this.fitToFrame && !this.ignoreResize(width, height)){
38716 if(this.fitContainer && this.resizeEl != this.el){
38717 this.el.setSize(width, height);
38719 var size = this.adjustForComponents(width, height);
38720 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
38721 this.fireEvent('resize', this, size.width, size.height);
38726 * Returns this panel's title
38729 getTitle : function(){
38731 if (typeof(this.title) != 'object') {
38736 for (var k in this.title) {
38737 if (!this.title.hasOwnProperty(k)) {
38741 if (k.indexOf('-') >= 0) {
38742 var s = k.split('-');
38743 for (var i = 0; i<s.length; i++) {
38744 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
38747 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
38754 * Set this panel's title
38755 * @param {String} title
38757 setTitle : function(title){
38758 this.title = title;
38760 this.region.updatePanelTitle(this, title);
38765 * Returns true is this panel was configured to be closable
38766 * @return {Boolean}
38768 isClosable : function(){
38769 return this.closable;
38772 beforeSlide : function(){
38774 this.resizeEl.clip();
38777 afterSlide : function(){
38779 this.resizeEl.unclip();
38783 * Force a content refresh from the URL specified in the {@link #setUrl} method.
38784 * Will fail silently if the {@link #setUrl} method has not been called.
38785 * This does not activate the panel, just updates its content.
38787 refresh : function(){
38788 if(this.refreshDelegate){
38789 this.loaded = false;
38790 this.refreshDelegate();
38795 * Destroys this panel
38797 destroy : function(){
38798 this.el.removeAllListeners();
38799 var tempEl = document.createElement("span");
38800 tempEl.appendChild(this.el.dom);
38801 tempEl.innerHTML = "";
38807 * form - if the content panel contains a form - this is a reference to it.
38808 * @type {Roo.form.Form}
38812 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
38813 * This contains a reference to it.
38819 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
38829 * @param {Object} cfg Xtype definition of item to add.
38833 getChildContainer: function () {
38834 return this.getEl();
38839 var ret = new Roo.factory(cfg);
38844 if (cfg.xtype.match(/^Form$/)) {
38847 //if (this.footer) {
38848 // el = this.footer.container.insertSibling(false, 'before');
38850 el = this.el.createChild();
38853 this.form = new Roo.form.Form(cfg);
38856 if ( this.form.allItems.length) {
38857 this.form.render(el.dom);
38861 // should only have one of theses..
38862 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
38863 // views.. should not be just added - used named prop 'view''
38865 cfg.el = this.el.appendChild(document.createElement("div"));
38868 var ret = new Roo.factory(cfg);
38870 ret.render && ret.render(false, ''); // render blank..
38880 * @class Roo.bootstrap.panel.Grid
38881 * @extends Roo.bootstrap.panel.Content
38883 * Create a new GridPanel.
38884 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
38885 * @param {Object} config A the config object
38891 Roo.bootstrap.panel.Grid = function(config)
38895 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
38896 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
38898 config.el = this.wrapper;
38899 //this.el = this.wrapper;
38901 if (config.container) {
38902 // ctor'ed from a Border/panel.grid
38905 this.wrapper.setStyle("overflow", "hidden");
38906 this.wrapper.addClass('roo-grid-container');
38911 if(config.toolbar){
38912 var tool_el = this.wrapper.createChild();
38913 this.toolbar = Roo.factory(config.toolbar);
38915 if (config.toolbar.items) {
38916 ti = config.toolbar.items ;
38917 delete config.toolbar.items ;
38921 this.toolbar.render(tool_el);
38922 for(var i =0;i < ti.length;i++) {
38923 // Roo.log(['add child', items[i]]);
38924 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
38926 this.toolbar.items = nitems;
38928 delete config.toolbar;
38931 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
38932 config.grid.scrollBody = true;;
38933 config.grid.monitorWindowResize = false; // turn off autosizing
38934 config.grid.autoHeight = false;
38935 config.grid.autoWidth = false;
38937 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
38939 if (config.background) {
38940 // render grid on panel activation (if panel background)
38941 this.on('activate', function(gp) {
38942 if (!gp.grid.rendered) {
38943 gp.grid.render(this.wrapper);
38944 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
38949 this.grid.render(this.wrapper);
38950 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
38953 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
38954 // ??? needed ??? config.el = this.wrapper;
38959 // xtype created footer. - not sure if will work as we normally have to render first..
38960 if (this.footer && !this.footer.el && this.footer.xtype) {
38962 var ctr = this.grid.getView().getFooterPanel(true);
38963 this.footer.dataSource = this.grid.dataSource;
38964 this.footer = Roo.factory(this.footer, Roo);
38965 this.footer.render(ctr);
38975 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
38976 getId : function(){
38977 return this.grid.id;
38981 * Returns the grid for this panel
38982 * @return {Roo.bootstrap.Table}
38984 getGrid : function(){
38988 setSize : function(width, height){
38989 if(!this.ignoreResize(width, height)){
38990 var grid = this.grid;
38991 var size = this.adjustForComponents(width, height);
38992 var gridel = grid.getGridEl();
38993 gridel.setSize(size.width, size.height);
38995 var thd = grid.getGridEl().select('thead',true).first();
38996 var tbd = grid.getGridEl().select('tbody', true).first();
38998 tbd.setSize(width, height - thd.getHeight());
39007 beforeSlide : function(){
39008 this.grid.getView().scroller.clip();
39011 afterSlide : function(){
39012 this.grid.getView().scroller.unclip();
39015 destroy : function(){
39016 this.grid.destroy();
39018 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
39023 * @class Roo.bootstrap.panel.Nest
39024 * @extends Roo.bootstrap.panel.Content
39026 * Create a new Panel, that can contain a layout.Border.
39029 * @param {Roo.BorderLayout} layout The layout for this panel
39030 * @param {String/Object} config A string to set only the title or a config object
39032 Roo.bootstrap.panel.Nest = function(config)
39034 // construct with only one argument..
39035 /* FIXME - implement nicer consturctors
39036 if (layout.layout) {
39038 layout = config.layout;
39039 delete config.layout;
39041 if (layout.xtype && !layout.getEl) {
39042 // then layout needs constructing..
39043 layout = Roo.factory(layout, Roo);
39047 config.el = config.layout.getEl();
39049 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
39051 config.layout.monitorWindowResize = false; // turn off autosizing
39052 this.layout = config.layout;
39053 this.layout.getEl().addClass("roo-layout-nested-layout");
39054 this.layout.parent = this;
39061 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
39063 setSize : function(width, height){
39064 if(!this.ignoreResize(width, height)){
39065 var size = this.adjustForComponents(width, height);
39066 var el = this.layout.getEl();
39067 if (size.height < 1) {
39068 el.setWidth(size.width);
39070 el.setSize(size.width, size.height);
39072 var touch = el.dom.offsetWidth;
39073 this.layout.layout();
39074 // ie requires a double layout on the first pass
39075 if(Roo.isIE && !this.initialized){
39076 this.initialized = true;
39077 this.layout.layout();
39082 // activate all subpanels if not currently active..
39084 setActiveState : function(active){
39085 this.active = active;
39086 this.setActiveClass(active);
39089 this.fireEvent("deactivate", this);
39093 this.fireEvent("activate", this);
39094 // not sure if this should happen before or after..
39095 if (!this.layout) {
39096 return; // should not happen..
39099 for (var r in this.layout.regions) {
39100 reg = this.layout.getRegion(r);
39101 if (reg.getActivePanel()) {
39102 //reg.showPanel(reg.getActivePanel()); // force it to activate..
39103 reg.setActivePanel(reg.getActivePanel());
39106 if (!reg.panels.length) {
39109 reg.showPanel(reg.getPanel(0));
39118 * Returns the nested BorderLayout for this panel
39119 * @return {Roo.BorderLayout}
39121 getLayout : function(){
39122 return this.layout;
39126 * Adds a xtype elements to the layout of the nested panel
39130 xtype : 'ContentPanel',
39137 xtype : 'NestedLayoutPanel',
39143 items : [ ... list of content panels or nested layout panels.. ]
39147 * @param {Object} cfg Xtype definition of item to add.
39149 addxtype : function(cfg) {
39150 return this.layout.addxtype(cfg);
39155 * Ext JS Library 1.1.1
39156 * Copyright(c) 2006-2007, Ext JS, LLC.
39158 * Originally Released Under LGPL - original licence link has changed is not relivant.
39161 * <script type="text/javascript">
39164 * @class Roo.TabPanel
39165 * @extends Roo.util.Observable
39166 * A lightweight tab container.
39170 // basic tabs 1, built from existing content
39171 var tabs = new Roo.TabPanel("tabs1");
39172 tabs.addTab("script", "View Script");
39173 tabs.addTab("markup", "View Markup");
39174 tabs.activate("script");
39176 // more advanced tabs, built from javascript
39177 var jtabs = new Roo.TabPanel("jtabs");
39178 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
39180 // set up the UpdateManager
39181 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
39182 var updater = tab2.getUpdateManager();
39183 updater.setDefaultUrl("ajax1.htm");
39184 tab2.on('activate', updater.refresh, updater, true);
39186 // Use setUrl for Ajax loading
39187 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
39188 tab3.setUrl("ajax2.htm", null, true);
39191 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
39194 jtabs.activate("jtabs-1");
39197 * Create a new TabPanel.
39198 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
39199 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
39201 Roo.bootstrap.panel.Tabs = function(config){
39203 * The container element for this TabPanel.
39204 * @type Roo.Element
39206 this.el = Roo.get(config.el);
39209 if(typeof config == "boolean"){
39210 this.tabPosition = config ? "bottom" : "top";
39212 Roo.apply(this, config);
39216 if(this.tabPosition == "bottom"){
39217 // if tabs are at the bottom = create the body first.
39218 this.bodyEl = Roo.get(this.createBody(this.el.dom));
39219 this.el.addClass("roo-tabs-bottom");
39221 // next create the tabs holders
39223 if (this.tabPosition == "west"){
39225 var reg = this.region; // fake it..
39227 if (!reg.mgr.parent) {
39230 reg = reg.mgr.parent.region;
39232 Roo.log("got nest?");
39234 if (reg.mgr.getRegion('west')) {
39235 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
39236 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
39237 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
39238 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
39239 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
39247 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
39248 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
39249 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
39250 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
39255 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
39258 // finally - if tabs are at the top, then create the body last..
39259 if(this.tabPosition != "bottom"){
39260 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
39261 * @type Roo.Element
39263 this.bodyEl = Roo.get(this.createBody(this.el.dom));
39264 this.el.addClass("roo-tabs-top");
39268 this.bodyEl.setStyle("position", "relative");
39270 this.active = null;
39271 this.activateDelegate = this.activate.createDelegate(this);
39276 * Fires when the active tab changes
39277 * @param {Roo.TabPanel} this
39278 * @param {Roo.TabPanelItem} activePanel The new active tab
39282 * @event beforetabchange
39283 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
39284 * @param {Roo.TabPanel} this
39285 * @param {Object} e Set cancel to true on this object to cancel the tab change
39286 * @param {Roo.TabPanelItem} tab The tab being changed to
39288 "beforetabchange" : true
39291 Roo.EventManager.onWindowResize(this.onResize, this);
39292 this.cpad = this.el.getPadding("lr");
39293 this.hiddenCount = 0;
39296 // toolbar on the tabbar support...
39297 if (this.toolbar) {
39298 alert("no toolbar support yet");
39299 this.toolbar = false;
39301 var tcfg = this.toolbar;
39302 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
39303 this.toolbar = new Roo.Toolbar(tcfg);
39304 if (Roo.isSafari) {
39305 var tbl = tcfg.container.child('table', true);
39306 tbl.setAttribute('width', '100%');
39314 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
39317 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
39319 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
39321 tabPosition : "top",
39323 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
39325 currentTabWidth : 0,
39327 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
39331 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
39335 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
39337 preferredTabWidth : 175,
39339 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
39341 resizeTabs : false,
39343 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
39345 monitorResize : true,
39347 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
39349 toolbar : false, // set by caller..
39351 region : false, /// set by caller
39353 disableTooltips : true, // not used yet...
39356 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
39357 * @param {String} id The id of the div to use <b>or create</b>
39358 * @param {String} text The text for the tab
39359 * @param {String} content (optional) Content to put in the TabPanelItem body
39360 * @param {Boolean} closable (optional) True to create a close icon on the tab
39361 * @return {Roo.TabPanelItem} The created TabPanelItem
39363 addTab : function(id, text, content, closable, tpl)
39365 var item = new Roo.bootstrap.panel.TabItem({
39369 closable : closable,
39372 this.addTabItem(item);
39374 item.setContent(content);
39380 * Returns the {@link Roo.TabPanelItem} with the specified id/index
39381 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
39382 * @return {Roo.TabPanelItem}
39384 getTab : function(id){
39385 return this.items[id];
39389 * Hides the {@link Roo.TabPanelItem} with the specified id/index
39390 * @param {String/Number} id The id or index of the TabPanelItem to hide.
39392 hideTab : function(id){
39393 var t = this.items[id];
39396 this.hiddenCount++;
39397 this.autoSizeTabs();
39402 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
39403 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
39405 unhideTab : function(id){
39406 var t = this.items[id];
39408 t.setHidden(false);
39409 this.hiddenCount--;
39410 this.autoSizeTabs();
39415 * Adds an existing {@link Roo.TabPanelItem}.
39416 * @param {Roo.TabPanelItem} item The TabPanelItem to add
39418 addTabItem : function(item)
39420 this.items[item.id] = item;
39421 this.items.push(item);
39422 this.autoSizeTabs();
39423 // if(this.resizeTabs){
39424 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
39425 // this.autoSizeTabs();
39427 // item.autoSize();
39432 * Removes a {@link Roo.TabPanelItem}.
39433 * @param {String/Number} id The id or index of the TabPanelItem to remove.
39435 removeTab : function(id){
39436 var items = this.items;
39437 var tab = items[id];
39438 if(!tab) { return; }
39439 var index = items.indexOf(tab);
39440 if(this.active == tab && items.length > 1){
39441 var newTab = this.getNextAvailable(index);
39446 this.stripEl.dom.removeChild(tab.pnode.dom);
39447 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
39448 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
39450 items.splice(index, 1);
39451 delete this.items[tab.id];
39452 tab.fireEvent("close", tab);
39453 tab.purgeListeners();
39454 this.autoSizeTabs();
39457 getNextAvailable : function(start){
39458 var items = this.items;
39460 // look for a next tab that will slide over to
39461 // replace the one being removed
39462 while(index < items.length){
39463 var item = items[++index];
39464 if(item && !item.isHidden()){
39468 // if one isn't found select the previous tab (on the left)
39471 var item = items[--index];
39472 if(item && !item.isHidden()){
39480 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
39481 * @param {String/Number} id The id or index of the TabPanelItem to disable.
39483 disableTab : function(id){
39484 var tab = this.items[id];
39485 if(tab && this.active != tab){
39491 * Enables a {@link Roo.TabPanelItem} that is disabled.
39492 * @param {String/Number} id The id or index of the TabPanelItem to enable.
39494 enableTab : function(id){
39495 var tab = this.items[id];
39500 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
39501 * @param {String/Number} id The id or index of the TabPanelItem to activate.
39502 * @return {Roo.TabPanelItem} The TabPanelItem.
39504 activate : function(id)
39506 //Roo.log('activite:' + id);
39508 var tab = this.items[id];
39512 if(tab == this.active || tab.disabled){
39516 this.fireEvent("beforetabchange", this, e, tab);
39517 if(e.cancel !== true && !tab.disabled){
39519 this.active.hide();
39521 this.active = this.items[id];
39522 this.active.show();
39523 this.fireEvent("tabchange", this, this.active);
39529 * Gets the active {@link Roo.TabPanelItem}.
39530 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
39532 getActiveTab : function(){
39533 return this.active;
39537 * Updates the tab body element to fit the height of the container element
39538 * for overflow scrolling
39539 * @param {Number} targetHeight (optional) Override the starting height from the elements height
39541 syncHeight : function(targetHeight){
39542 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
39543 var bm = this.bodyEl.getMargins();
39544 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
39545 this.bodyEl.setHeight(newHeight);
39549 onResize : function(){
39550 if(this.monitorResize){
39551 this.autoSizeTabs();
39556 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
39558 beginUpdate : function(){
39559 this.updating = true;
39563 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
39565 endUpdate : function(){
39566 this.updating = false;
39567 this.autoSizeTabs();
39571 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
39573 autoSizeTabs : function()
39575 var count = this.items.length;
39576 var vcount = count - this.hiddenCount;
39579 this.stripEl.hide();
39581 this.stripEl.show();
39584 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
39589 var w = Math.max(this.el.getWidth() - this.cpad, 10);
39590 var availWidth = Math.floor(w / vcount);
39591 var b = this.stripBody;
39592 if(b.getWidth() > w){
39593 var tabs = this.items;
39594 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
39595 if(availWidth < this.minTabWidth){
39596 /*if(!this.sleft){ // incomplete scrolling code
39597 this.createScrollButtons();
39600 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
39603 if(this.currentTabWidth < this.preferredTabWidth){
39604 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
39610 * Returns the number of tabs in this TabPanel.
39613 getCount : function(){
39614 return this.items.length;
39618 * Resizes all the tabs to the passed width
39619 * @param {Number} The new width
39621 setTabWidth : function(width){
39622 this.currentTabWidth = width;
39623 for(var i = 0, len = this.items.length; i < len; i++) {
39624 if(!this.items[i].isHidden()) {
39625 this.items[i].setWidth(width);
39631 * Destroys this TabPanel
39632 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
39634 destroy : function(removeEl){
39635 Roo.EventManager.removeResizeListener(this.onResize, this);
39636 for(var i = 0, len = this.items.length; i < len; i++){
39637 this.items[i].purgeListeners();
39639 if(removeEl === true){
39640 this.el.update("");
39645 createStrip : function(container)
39647 var strip = document.createElement("nav");
39648 strip.className = Roo.bootstrap.version == 4 ?
39649 "navbar-light bg-light" :
39650 "navbar navbar-default"; //"x-tabs-wrap";
39651 container.appendChild(strip);
39655 createStripList : function(strip)
39657 // div wrapper for retard IE
39658 // returns the "tr" element.
39659 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
39660 //'<div class="x-tabs-strip-wrap">'+
39661 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
39662 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
39663 return strip.firstChild; //.firstChild.firstChild.firstChild;
39665 createBody : function(container)
39667 var body = document.createElement("div");
39668 Roo.id(body, "tab-body");
39669 //Roo.fly(body).addClass("x-tabs-body");
39670 Roo.fly(body).addClass("tab-content");
39671 container.appendChild(body);
39674 createItemBody :function(bodyEl, id){
39675 var body = Roo.getDom(id);
39677 body = document.createElement("div");
39680 //Roo.fly(body).addClass("x-tabs-item-body");
39681 Roo.fly(body).addClass("tab-pane");
39682 bodyEl.insertBefore(body, bodyEl.firstChild);
39686 createStripElements : function(stripEl, text, closable, tpl)
39688 var td = document.createElement("li"); // was td..
39689 td.className = 'nav-item';
39691 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
39694 stripEl.appendChild(td);
39696 td.className = "x-tabs-closable";
39697 if(!this.closeTpl){
39698 this.closeTpl = new Roo.Template(
39699 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
39700 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
39701 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
39704 var el = this.closeTpl.overwrite(td, {"text": text});
39705 var close = el.getElementsByTagName("div")[0];
39706 var inner = el.getElementsByTagName("em")[0];
39707 return {"el": el, "close": close, "inner": inner};
39710 // not sure what this is..
39711 // if(!this.tabTpl){
39712 //this.tabTpl = new Roo.Template(
39713 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
39714 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
39716 // this.tabTpl = new Roo.Template(
39717 // '<a href="#">' +
39718 // '<span unselectable="on"' +
39719 // (this.disableTooltips ? '' : ' title="{text}"') +
39720 // ' >{text}</span></a>'
39726 var template = tpl || this.tabTpl || false;
39729 template = new Roo.Template(
39730 Roo.bootstrap.version == 4 ?
39732 '<a class="nav-link" href="#" unselectable="on"' +
39733 (this.disableTooltips ? '' : ' title="{text}"') +
39736 '<a class="nav-link" href="#">' +
39737 '<span unselectable="on"' +
39738 (this.disableTooltips ? '' : ' title="{text}"') +
39739 ' >{text}</span></a>'
39744 switch (typeof(template)) {
39748 template = new Roo.Template(template);
39754 var el = template.overwrite(td, {"text": text});
39756 var inner = el.getElementsByTagName("span")[0];
39758 return {"el": el, "inner": inner};
39766 * @class Roo.TabPanelItem
39767 * @extends Roo.util.Observable
39768 * Represents an individual item (tab plus body) in a TabPanel.
39769 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
39770 * @param {String} id The id of this TabPanelItem
39771 * @param {String} text The text for the tab of this TabPanelItem
39772 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
39774 Roo.bootstrap.panel.TabItem = function(config){
39776 * The {@link Roo.TabPanel} this TabPanelItem belongs to
39777 * @type Roo.TabPanel
39779 this.tabPanel = config.panel;
39781 * The id for this TabPanelItem
39784 this.id = config.id;
39786 this.disabled = false;
39788 this.text = config.text;
39790 this.loaded = false;
39791 this.closable = config.closable;
39794 * The body element for this TabPanelItem.
39795 * @type Roo.Element
39797 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
39798 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
39799 this.bodyEl.setStyle("display", "block");
39800 this.bodyEl.setStyle("zoom", "1");
39801 //this.hideAction();
39803 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
39805 this.el = Roo.get(els.el);
39806 this.inner = Roo.get(els.inner, true);
39807 this.textEl = Roo.bootstrap.version == 4 ?
39808 this.el : Roo.get(this.el.dom.firstChild, true);
39810 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
39811 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
39814 // this.el.on("mousedown", this.onTabMouseDown, this);
39815 this.el.on("click", this.onTabClick, this);
39817 if(config.closable){
39818 var c = Roo.get(els.close, true);
39819 c.dom.title = this.closeText;
39820 c.addClassOnOver("close-over");
39821 c.on("click", this.closeClick, this);
39827 * Fires when this tab becomes the active tab.
39828 * @param {Roo.TabPanel} tabPanel The parent TabPanel
39829 * @param {Roo.TabPanelItem} this
39833 * @event beforeclose
39834 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
39835 * @param {Roo.TabPanelItem} this
39836 * @param {Object} e Set cancel to true on this object to cancel the close.
39838 "beforeclose": true,
39841 * Fires when this tab is closed.
39842 * @param {Roo.TabPanelItem} this
39846 * @event deactivate
39847 * Fires when this tab is no longer the active tab.
39848 * @param {Roo.TabPanel} tabPanel The parent TabPanel
39849 * @param {Roo.TabPanelItem} this
39851 "deactivate" : true
39853 this.hidden = false;
39855 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
39858 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
39860 purgeListeners : function(){
39861 Roo.util.Observable.prototype.purgeListeners.call(this);
39862 this.el.removeAllListeners();
39865 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
39868 this.status_node.addClass("active");
39871 this.tabPanel.stripWrap.repaint();
39873 this.fireEvent("activate", this.tabPanel, this);
39877 * Returns true if this tab is the active tab.
39878 * @return {Boolean}
39880 isActive : function(){
39881 return this.tabPanel.getActiveTab() == this;
39885 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
39888 this.status_node.removeClass("active");
39890 this.fireEvent("deactivate", this.tabPanel, this);
39893 hideAction : function(){
39894 this.bodyEl.hide();
39895 this.bodyEl.setStyle("position", "absolute");
39896 this.bodyEl.setLeft("-20000px");
39897 this.bodyEl.setTop("-20000px");
39900 showAction : function(){
39901 this.bodyEl.setStyle("position", "relative");
39902 this.bodyEl.setTop("");
39903 this.bodyEl.setLeft("");
39904 this.bodyEl.show();
39908 * Set the tooltip for the tab.
39909 * @param {String} tooltip The tab's tooltip
39911 setTooltip : function(text){
39912 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
39913 this.textEl.dom.qtip = text;
39914 this.textEl.dom.removeAttribute('title');
39916 this.textEl.dom.title = text;
39920 onTabClick : function(e){
39921 e.preventDefault();
39922 this.tabPanel.activate(this.id);
39925 onTabMouseDown : function(e){
39926 e.preventDefault();
39927 this.tabPanel.activate(this.id);
39930 getWidth : function(){
39931 return this.inner.getWidth();
39934 setWidth : function(width){
39935 var iwidth = width - this.linode.getPadding("lr");
39936 this.inner.setWidth(iwidth);
39937 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
39938 this.linode.setWidth(width);
39942 * Show or hide the tab
39943 * @param {Boolean} hidden True to hide or false to show.
39945 setHidden : function(hidden){
39946 this.hidden = hidden;
39947 this.linode.setStyle("display", hidden ? "none" : "");
39951 * Returns true if this tab is "hidden"
39952 * @return {Boolean}
39954 isHidden : function(){
39955 return this.hidden;
39959 * Returns the text for this tab
39962 getText : function(){
39966 autoSize : function(){
39967 //this.el.beginMeasure();
39968 this.textEl.setWidth(1);
39970 * #2804 [new] Tabs in Roojs
39971 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
39973 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
39974 //this.el.endMeasure();
39978 * Sets the text for the tab (Note: this also sets the tooltip text)
39979 * @param {String} text The tab's text and tooltip
39981 setText : function(text){
39983 this.textEl.update(text);
39984 this.setTooltip(text);
39985 //if(!this.tabPanel.resizeTabs){
39986 // this.autoSize();
39990 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
39992 activate : function(){
39993 this.tabPanel.activate(this.id);
39997 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
39999 disable : function(){
40000 if(this.tabPanel.active != this){
40001 this.disabled = true;
40002 this.status_node.addClass("disabled");
40007 * Enables this TabPanelItem if it was previously disabled.
40009 enable : function(){
40010 this.disabled = false;
40011 this.status_node.removeClass("disabled");
40015 * Sets the content for this TabPanelItem.
40016 * @param {String} content The content
40017 * @param {Boolean} loadScripts true to look for and load scripts
40019 setContent : function(content, loadScripts){
40020 this.bodyEl.update(content, loadScripts);
40024 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
40025 * @return {Roo.UpdateManager} The UpdateManager
40027 getUpdateManager : function(){
40028 return this.bodyEl.getUpdateManager();
40032 * Set a URL to be used to load the content for this TabPanelItem.
40033 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
40034 * @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)
40035 * @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)
40036 * @return {Roo.UpdateManager} The UpdateManager
40038 setUrl : function(url, params, loadOnce){
40039 if(this.refreshDelegate){
40040 this.un('activate', this.refreshDelegate);
40042 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
40043 this.on("activate", this.refreshDelegate);
40044 return this.bodyEl.getUpdateManager();
40048 _handleRefresh : function(url, params, loadOnce){
40049 if(!loadOnce || !this.loaded){
40050 var updater = this.bodyEl.getUpdateManager();
40051 updater.update(url, params, this._setLoaded.createDelegate(this));
40056 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
40057 * Will fail silently if the setUrl method has not been called.
40058 * This does not activate the panel, just updates its content.
40060 refresh : function(){
40061 if(this.refreshDelegate){
40062 this.loaded = false;
40063 this.refreshDelegate();
40068 _setLoaded : function(){
40069 this.loaded = true;
40073 closeClick : function(e){
40076 this.fireEvent("beforeclose", this, o);
40077 if(o.cancel !== true){
40078 this.tabPanel.removeTab(this.id);
40082 * The text displayed in the tooltip for the close icon.
40085 closeText : "Close this tab"
40088 * This script refer to:
40089 * Title: International Telephone Input
40090 * Author: Jack O'Connor
40091 * Code version: v12.1.12
40092 * Availability: https://github.com/jackocnr/intl-tel-input.git
40095 Roo.bootstrap.PhoneInputData = function() {
40098 "Afghanistan (افغانستان)",
40103 "Albania (Shqipëri)",
40108 "Algeria (الجزائر)",
40133 "Antigua and Barbuda",
40143 "Armenia (Հայաստան)",
40159 "Austria (Österreich)",
40164 "Azerbaijan (Azərbaycan)",
40174 "Bahrain (البحرين)",
40179 "Bangladesh (বাংলাদেশ)",
40189 "Belarus (Беларусь)",
40194 "Belgium (België)",
40224 "Bosnia and Herzegovina (Босна и Херцеговина)",
40239 "British Indian Ocean Territory",
40244 "British Virgin Islands",
40254 "Bulgaria (България)",
40264 "Burundi (Uburundi)",
40269 "Cambodia (កម្ពុជា)",
40274 "Cameroon (Cameroun)",
40283 ["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"]
40286 "Cape Verde (Kabu Verdi)",
40291 "Caribbean Netherlands",
40302 "Central African Republic (République centrafricaine)",
40322 "Christmas Island",
40328 "Cocos (Keeling) Islands",
40339 "Comoros (جزر القمر)",
40344 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
40349 "Congo (Republic) (Congo-Brazzaville)",
40369 "Croatia (Hrvatska)",
40390 "Czech Republic (Česká republika)",
40395 "Denmark (Danmark)",
40410 "Dominican Republic (República Dominicana)",
40414 ["809", "829", "849"]
40432 "Equatorial Guinea (Guinea Ecuatorial)",
40452 "Falkland Islands (Islas Malvinas)",
40457 "Faroe Islands (Føroyar)",
40478 "French Guiana (Guyane française)",
40483 "French Polynesia (Polynésie française)",
40498 "Georgia (საქართველო)",
40503 "Germany (Deutschland)",
40523 "Greenland (Kalaallit Nunaat)",
40560 "Guinea-Bissau (Guiné Bissau)",
40585 "Hungary (Magyarország)",
40590 "Iceland (Ísland)",
40610 "Iraq (العراق)",
40626 "Israel (ישראל)",
40653 "Jordan (الأردن)",
40658 "Kazakhstan (Казахстан)",
40679 "Kuwait (الكويت)",
40684 "Kyrgyzstan (Кыргызстан)",
40694 "Latvia (Latvija)",
40699 "Lebanon (لبنان)",
40714 "Libya (ليبيا)",
40724 "Lithuania (Lietuva)",
40739 "Macedonia (FYROM) (Македонија)",
40744 "Madagascar (Madagasikara)",
40774 "Marshall Islands",
40784 "Mauritania (موريتانيا)",
40789 "Mauritius (Moris)",
40810 "Moldova (Republica Moldova)",
40820 "Mongolia (Монгол)",
40825 "Montenegro (Crna Gora)",
40835 "Morocco (المغرب)",
40841 "Mozambique (Moçambique)",
40846 "Myanmar (Burma) (မြန်မာ)",
40851 "Namibia (Namibië)",
40866 "Netherlands (Nederland)",
40871 "New Caledonia (Nouvelle-Calédonie)",
40906 "North Korea (조선 민주주의 인민 공화국)",
40911 "Northern Mariana Islands",
40927 "Pakistan (پاکستان)",
40937 "Palestine (فلسطين)",
40947 "Papua New Guinea",
40989 "Réunion (La Réunion)",
40995 "Romania (România)",
41011 "Saint Barthélemy",
41022 "Saint Kitts and Nevis",
41032 "Saint Martin (Saint-Martin (partie française))",
41038 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
41043 "Saint Vincent and the Grenadines",
41058 "São Tomé and Príncipe (São Tomé e Príncipe)",
41063 "Saudi Arabia (المملكة العربية السعودية)",
41068 "Senegal (Sénégal)",
41098 "Slovakia (Slovensko)",
41103 "Slovenia (Slovenija)",
41113 "Somalia (Soomaaliya)",
41123 "South Korea (대한민국)",
41128 "South Sudan (جنوب السودان)",
41138 "Sri Lanka (ශ්රී ලංකාව)",
41143 "Sudan (السودان)",
41153 "Svalbard and Jan Mayen",
41164 "Sweden (Sverige)",
41169 "Switzerland (Schweiz)",
41174 "Syria (سوريا)",
41219 "Trinidad and Tobago",
41224 "Tunisia (تونس)",
41229 "Turkey (Türkiye)",
41239 "Turks and Caicos Islands",
41249 "U.S. Virgin Islands",
41259 "Ukraine (Україна)",
41264 "United Arab Emirates (الإمارات العربية المتحدة)",
41286 "Uzbekistan (Oʻzbekiston)",
41296 "Vatican City (Città del Vaticano)",
41307 "Vietnam (Việt Nam)",
41312 "Wallis and Futuna (Wallis-et-Futuna)",
41317 "Western Sahara (الصحراء الغربية)",
41323 "Yemen (اليمن)",
41347 * This script refer to:
41348 * Title: International Telephone Input
41349 * Author: Jack O'Connor
41350 * Code version: v12.1.12
41351 * Availability: https://github.com/jackocnr/intl-tel-input.git
41355 * @class Roo.bootstrap.PhoneInput
41356 * @extends Roo.bootstrap.TriggerField
41357 * An input with International dial-code selection
41359 * @cfg {String} defaultDialCode default '+852'
41360 * @cfg {Array} preferedCountries default []
41363 * Create a new PhoneInput.
41364 * @param {Object} config Configuration options
41367 Roo.bootstrap.PhoneInput = function(config) {
41368 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
41371 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
41373 listWidth: undefined,
41375 selectedClass: 'active',
41377 invalidClass : "has-warning",
41379 validClass: 'has-success',
41381 allowed: '0123456789',
41386 * @cfg {String} defaultDialCode The default dial code when initializing the input
41388 defaultDialCode: '+852',
41391 * @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
41393 preferedCountries: false,
41395 getAutoCreate : function()
41397 var data = Roo.bootstrap.PhoneInputData();
41398 var align = this.labelAlign || this.parentLabelAlign();
41401 this.allCountries = [];
41402 this.dialCodeMapping = [];
41404 for (var i = 0; i < data.length; i++) {
41406 this.allCountries[i] = {
41410 priority: c[3] || 0,
41411 areaCodes: c[4] || null
41413 this.dialCodeMapping[c[2]] = {
41416 priority: c[3] || 0,
41417 areaCodes: c[4] || null
41429 // type: 'number', -- do not use number - we get the flaky up/down arrows.
41430 maxlength: this.max_length,
41431 cls : 'form-control tel-input',
41432 autocomplete: 'new-password'
41435 var hiddenInput = {
41438 cls: 'hidden-tel-input'
41442 hiddenInput.name = this.name;
41445 if (this.disabled) {
41446 input.disabled = true;
41449 var flag_container = {
41466 cls: this.hasFeedback ? 'has-feedback' : '',
41472 cls: 'dial-code-holder',
41479 cls: 'roo-select2-container input-group',
41486 if (this.fieldLabel.length) {
41489 tooltip: 'This field is required'
41495 cls: 'control-label',
41501 html: this.fieldLabel
41504 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41510 if(this.indicatorpos == 'right') {
41511 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41518 if(align == 'left') {
41526 if(this.labelWidth > 12){
41527 label.style = "width: " + this.labelWidth + 'px';
41529 if(this.labelWidth < 13 && this.labelmd == 0){
41530 this.labelmd = this.labelWidth;
41532 if(this.labellg > 0){
41533 label.cls += ' col-lg-' + this.labellg;
41534 input.cls += ' col-lg-' + (12 - this.labellg);
41536 if(this.labelmd > 0){
41537 label.cls += ' col-md-' + this.labelmd;
41538 container.cls += ' col-md-' + (12 - this.labelmd);
41540 if(this.labelsm > 0){
41541 label.cls += ' col-sm-' + this.labelsm;
41542 container.cls += ' col-sm-' + (12 - this.labelsm);
41544 if(this.labelxs > 0){
41545 label.cls += ' col-xs-' + this.labelxs;
41546 container.cls += ' col-xs-' + (12 - this.labelxs);
41556 var settings = this;
41558 ['xs','sm','md','lg'].map(function(size){
41559 if (settings[size]) {
41560 cfg.cls += ' col-' + size + '-' + settings[size];
41564 this.store = new Roo.data.Store({
41565 proxy : new Roo.data.MemoryProxy({}),
41566 reader : new Roo.data.JsonReader({
41577 'name' : 'dialCode',
41581 'name' : 'priority',
41585 'name' : 'areaCodes',
41592 if(!this.preferedCountries) {
41593 this.preferedCountries = [
41600 var p = this.preferedCountries.reverse();
41603 for (var i = 0; i < p.length; i++) {
41604 for (var j = 0; j < this.allCountries.length; j++) {
41605 if(this.allCountries[j].iso2 == p[i]) {
41606 var t = this.allCountries[j];
41607 this.allCountries.splice(j,1);
41608 this.allCountries.unshift(t);
41614 this.store.proxy.data = {
41616 data: this.allCountries
41622 initEvents : function()
41625 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
41627 this.indicator = this.indicatorEl();
41628 this.flag = this.flagEl();
41629 this.dialCodeHolder = this.dialCodeHolderEl();
41631 this.trigger = this.el.select('div.flag-box',true).first();
41632 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
41637 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41638 _this.list.setWidth(lw);
41641 this.list.on('mouseover', this.onViewOver, this);
41642 this.list.on('mousemove', this.onViewMove, this);
41643 this.inputEl().on("keyup", this.onKeyUp, this);
41644 this.inputEl().on("keypress", this.onKeyPress, this);
41646 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
41648 this.view = new Roo.View(this.list, this.tpl, {
41649 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41652 this.view.on('click', this.onViewClick, this);
41653 this.setValue(this.defaultDialCode);
41656 onTriggerClick : function(e)
41658 Roo.log('trigger click');
41663 if(this.isExpanded()){
41665 this.hasFocus = false;
41667 this.store.load({});
41668 this.hasFocus = true;
41673 isExpanded : function()
41675 return this.list.isVisible();
41678 collapse : function()
41680 if(!this.isExpanded()){
41684 Roo.get(document).un('mousedown', this.collapseIf, this);
41685 Roo.get(document).un('mousewheel', this.collapseIf, this);
41686 this.fireEvent('collapse', this);
41690 expand : function()
41694 if(this.isExpanded() || !this.hasFocus){
41698 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
41699 this.list.setWidth(lw);
41702 this.restrictHeight();
41704 Roo.get(document).on('mousedown', this.collapseIf, this);
41705 Roo.get(document).on('mousewheel', this.collapseIf, this);
41707 this.fireEvent('expand', this);
41710 restrictHeight : function()
41712 this.list.alignTo(this.inputEl(), this.listAlign);
41713 this.list.alignTo(this.inputEl(), this.listAlign);
41716 onViewOver : function(e, t)
41718 if(this.inKeyMode){
41721 var item = this.view.findItemFromChild(t);
41724 var index = this.view.indexOf(item);
41725 this.select(index, false);
41730 onViewClick : function(view, doFocus, el, e)
41732 var index = this.view.getSelectedIndexes()[0];
41734 var r = this.store.getAt(index);
41737 this.onSelect(r, index);
41739 if(doFocus !== false && !this.blockFocus){
41740 this.inputEl().focus();
41744 onViewMove : function(e, t)
41746 this.inKeyMode = false;
41749 select : function(index, scrollIntoView)
41751 this.selectedIndex = index;
41752 this.view.select(index);
41753 if(scrollIntoView !== false){
41754 var el = this.view.getNode(index);
41756 this.list.scrollChildIntoView(el, false);
41761 createList : function()
41763 this.list = Roo.get(document.body).createChild({
41765 cls: 'typeahead typeahead-long dropdown-menu tel-list',
41766 style: 'display:none'
41769 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
41772 collapseIf : function(e)
41774 var in_combo = e.within(this.el);
41775 var in_list = e.within(this.list);
41776 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
41778 if (in_combo || in_list || is_list) {
41784 onSelect : function(record, index)
41786 if(this.fireEvent('beforeselect', this, record, index) !== false){
41788 this.setFlagClass(record.data.iso2);
41789 this.setDialCode(record.data.dialCode);
41790 this.hasFocus = false;
41792 this.fireEvent('select', this, record, index);
41796 flagEl : function()
41798 var flag = this.el.select('div.flag',true).first();
41805 dialCodeHolderEl : function()
41807 var d = this.el.select('input.dial-code-holder',true).first();
41814 setDialCode : function(v)
41816 this.dialCodeHolder.dom.value = '+'+v;
41819 setFlagClass : function(n)
41821 this.flag.dom.className = 'flag '+n;
41824 getValue : function()
41826 var v = this.inputEl().getValue();
41827 if(this.dialCodeHolder) {
41828 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
41833 setValue : function(v)
41835 var d = this.getDialCode(v);
41837 //invalid dial code
41838 if(v.length == 0 || !d || d.length == 0) {
41840 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
41841 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41847 this.setFlagClass(this.dialCodeMapping[d].iso2);
41848 this.setDialCode(d);
41849 this.inputEl().dom.value = v.replace('+'+d,'');
41850 this.hiddenEl().dom.value = this.getValue();
41855 getDialCode : function(v)
41859 if (v.length == 0) {
41860 return this.dialCodeHolder.dom.value;
41864 if (v.charAt(0) != "+") {
41867 var numericChars = "";
41868 for (var i = 1; i < v.length; i++) {
41869 var c = v.charAt(i);
41872 if (this.dialCodeMapping[numericChars]) {
41873 dialCode = v.substr(1, i);
41875 if (numericChars.length == 4) {
41885 this.setValue(this.defaultDialCode);
41889 hiddenEl : function()
41891 return this.el.select('input.hidden-tel-input',true).first();
41894 // after setting val
41895 onKeyUp : function(e){
41896 this.setValue(this.getValue());
41899 onKeyPress : function(e){
41900 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
41907 * @class Roo.bootstrap.MoneyField
41908 * @extends Roo.bootstrap.ComboBox
41909 * Bootstrap MoneyField class
41912 * Create a new MoneyField.
41913 * @param {Object} config Configuration options
41916 Roo.bootstrap.MoneyField = function(config) {
41918 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
41922 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
41925 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
41927 allowDecimals : true,
41929 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
41931 decimalSeparator : ".",
41933 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
41935 decimalPrecision : 0,
41937 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
41939 allowNegative : true,
41941 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
41945 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
41947 minValue : Number.NEGATIVE_INFINITY,
41949 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
41951 maxValue : Number.MAX_VALUE,
41953 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
41955 minText : "The minimum value for this field is {0}",
41957 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
41959 maxText : "The maximum value for this field is {0}",
41961 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
41962 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
41964 nanText : "{0} is not a valid number",
41966 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
41970 * @cfg {String} defaults currency of the MoneyField
41971 * value should be in lkey
41973 defaultCurrency : false,
41975 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
41977 thousandsDelimiter : false,
41979 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
41990 getAutoCreate : function()
41992 var align = this.labelAlign || this.parentLabelAlign();
42004 cls : 'form-control roo-money-amount-input',
42005 autocomplete: 'new-password'
42008 var hiddenInput = {
42012 cls: 'hidden-number-input'
42015 if(this.max_length) {
42016 input.maxlength = this.max_length;
42020 hiddenInput.name = this.name;
42023 if (this.disabled) {
42024 input.disabled = true;
42027 var clg = 12 - this.inputlg;
42028 var cmd = 12 - this.inputmd;
42029 var csm = 12 - this.inputsm;
42030 var cxs = 12 - this.inputxs;
42034 cls : 'row roo-money-field',
42038 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
42042 cls: 'roo-select2-container input-group',
42046 cls : 'form-control roo-money-currency-input',
42047 autocomplete: 'new-password',
42049 name : this.currencyName
42053 cls : 'input-group-addon',
42067 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
42071 cls: this.hasFeedback ? 'has-feedback' : '',
42082 if (this.fieldLabel.length) {
42085 tooltip: 'This field is required'
42091 cls: 'control-label',
42097 html: this.fieldLabel
42100 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42106 if(this.indicatorpos == 'right') {
42107 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42114 if(align == 'left') {
42122 if(this.labelWidth > 12){
42123 label.style = "width: " + this.labelWidth + 'px';
42125 if(this.labelWidth < 13 && this.labelmd == 0){
42126 this.labelmd = this.labelWidth;
42128 if(this.labellg > 0){
42129 label.cls += ' col-lg-' + this.labellg;
42130 input.cls += ' col-lg-' + (12 - this.labellg);
42132 if(this.labelmd > 0){
42133 label.cls += ' col-md-' + this.labelmd;
42134 container.cls += ' col-md-' + (12 - this.labelmd);
42136 if(this.labelsm > 0){
42137 label.cls += ' col-sm-' + this.labelsm;
42138 container.cls += ' col-sm-' + (12 - this.labelsm);
42140 if(this.labelxs > 0){
42141 label.cls += ' col-xs-' + this.labelxs;
42142 container.cls += ' col-xs-' + (12 - this.labelxs);
42153 var settings = this;
42155 ['xs','sm','md','lg'].map(function(size){
42156 if (settings[size]) {
42157 cfg.cls += ' col-' + size + '-' + settings[size];
42164 initEvents : function()
42166 this.indicator = this.indicatorEl();
42168 this.initCurrencyEvent();
42170 this.initNumberEvent();
42173 initCurrencyEvent : function()
42176 throw "can not find store for combo";
42179 this.store = Roo.factory(this.store, Roo.data);
42180 this.store.parent = this;
42184 this.triggerEl = this.el.select('.input-group-addon', true).first();
42186 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
42191 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42192 _this.list.setWidth(lw);
42195 this.list.on('mouseover', this.onViewOver, this);
42196 this.list.on('mousemove', this.onViewMove, this);
42197 this.list.on('scroll', this.onViewScroll, this);
42200 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
42203 this.view = new Roo.View(this.list, this.tpl, {
42204 singleSelect:true, store: this.store, selectedClass: this.selectedClass
42207 this.view.on('click', this.onViewClick, this);
42209 this.store.on('beforeload', this.onBeforeLoad, this);
42210 this.store.on('load', this.onLoad, this);
42211 this.store.on('loadexception', this.onLoadException, this);
42213 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
42214 "up" : function(e){
42215 this.inKeyMode = true;
42219 "down" : function(e){
42220 if(!this.isExpanded()){
42221 this.onTriggerClick();
42223 this.inKeyMode = true;
42228 "enter" : function(e){
42231 if(this.fireEvent("specialkey", this, e)){
42232 this.onViewClick(false);
42238 "esc" : function(e){
42242 "tab" : function(e){
42245 if(this.fireEvent("specialkey", this, e)){
42246 this.onViewClick(false);
42254 doRelay : function(foo, bar, hname){
42255 if(hname == 'down' || this.scope.isExpanded()){
42256 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
42264 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
42268 initNumberEvent : function(e)
42270 this.inputEl().on("keydown" , this.fireKey, this);
42271 this.inputEl().on("focus", this.onFocus, this);
42272 this.inputEl().on("blur", this.onBlur, this);
42274 this.inputEl().relayEvent('keyup', this);
42276 if(this.indicator){
42277 this.indicator.addClass('invisible');
42280 this.originalValue = this.getValue();
42282 if(this.validationEvent == 'keyup'){
42283 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
42284 this.inputEl().on('keyup', this.filterValidation, this);
42286 else if(this.validationEvent !== false){
42287 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
42290 if(this.selectOnFocus){
42291 this.on("focus", this.preFocus, this);
42294 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
42295 this.inputEl().on("keypress", this.filterKeys, this);
42297 this.inputEl().relayEvent('keypress', this);
42300 var allowed = "0123456789";
42302 if(this.allowDecimals){
42303 allowed += this.decimalSeparator;
42306 if(this.allowNegative){
42310 if(this.thousandsDelimiter) {
42314 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
42316 var keyPress = function(e){
42318 var k = e.getKey();
42320 var c = e.getCharCode();
42323 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
42324 allowed.indexOf(String.fromCharCode(c)) === -1
42330 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
42334 if(allowed.indexOf(String.fromCharCode(c)) === -1){
42339 this.inputEl().on("keypress", keyPress, this);
42343 onTriggerClick : function(e)
42350 this.loadNext = false;
42352 if(this.isExpanded()){
42357 this.hasFocus = true;
42359 if(this.triggerAction == 'all') {
42360 this.doQuery(this.allQuery, true);
42364 this.doQuery(this.getRawValue());
42367 getCurrency : function()
42369 var v = this.currencyEl().getValue();
42374 restrictHeight : function()
42376 this.list.alignTo(this.currencyEl(), this.listAlign);
42377 this.list.alignTo(this.currencyEl(), this.listAlign);
42380 onViewClick : function(view, doFocus, el, e)
42382 var index = this.view.getSelectedIndexes()[0];
42384 var r = this.store.getAt(index);
42387 this.onSelect(r, index);
42391 onSelect : function(record, index){
42393 if(this.fireEvent('beforeselect', this, record, index) !== false){
42395 this.setFromCurrencyData(index > -1 ? record.data : false);
42399 this.fireEvent('select', this, record, index);
42403 setFromCurrencyData : function(o)
42407 this.lastCurrency = o;
42409 if (this.currencyField) {
42410 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
42412 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
42415 this.lastSelectionText = currency;
42417 //setting default currency
42418 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
42419 this.setCurrency(this.defaultCurrency);
42423 this.setCurrency(currency);
42426 setFromData : function(o)
42430 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
42432 this.setFromCurrencyData(c);
42437 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
42439 Roo.log('no value set for '+ (this.name ? this.name : this.id));
42442 this.setValue(value);
42446 setCurrency : function(v)
42448 this.currencyValue = v;
42451 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
42456 setValue : function(v)
42458 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
42464 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
42466 this.inputEl().dom.value = (v == '') ? '' :
42467 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
42469 if(!this.allowZero && v === '0') {
42470 this.hiddenEl().dom.value = '';
42471 this.inputEl().dom.value = '';
42478 getRawValue : function()
42480 var v = this.inputEl().getValue();
42485 getValue : function()
42487 return this.fixPrecision(this.parseValue(this.getRawValue()));
42490 parseValue : function(value)
42492 if(this.thousandsDelimiter) {
42494 r = new RegExp(",", "g");
42495 value = value.replace(r, "");
42498 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
42499 return isNaN(value) ? '' : value;
42503 fixPrecision : function(value)
42505 if(this.thousandsDelimiter) {
42507 r = new RegExp(",", "g");
42508 value = value.replace(r, "");
42511 var nan = isNaN(value);
42513 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
42514 return nan ? '' : value;
42516 return parseFloat(value).toFixed(this.decimalPrecision);
42519 decimalPrecisionFcn : function(v)
42521 return Math.floor(v);
42524 validateValue : function(value)
42526 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
42530 var num = this.parseValue(value);
42533 this.markInvalid(String.format(this.nanText, value));
42537 if(num < this.minValue){
42538 this.markInvalid(String.format(this.minText, this.minValue));
42542 if(num > this.maxValue){
42543 this.markInvalid(String.format(this.maxText, this.maxValue));
42550 validate : function()
42552 if(this.disabled || this.allowBlank){
42557 var currency = this.getCurrency();
42559 if(this.validateValue(this.getRawValue()) && currency.length){
42564 this.markInvalid();
42568 getName: function()
42573 beforeBlur : function()
42579 var v = this.parseValue(this.getRawValue());
42586 onBlur : function()
42590 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
42591 //this.el.removeClass(this.focusClass);
42594 this.hasFocus = false;
42596 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
42600 var v = this.getValue();
42602 if(String(v) !== String(this.startValue)){
42603 this.fireEvent('change', this, v, this.startValue);
42606 this.fireEvent("blur", this);
42609 inputEl : function()
42611 return this.el.select('.roo-money-amount-input', true).first();
42614 currencyEl : function()
42616 return this.el.select('.roo-money-currency-input', true).first();
42619 hiddenEl : function()
42621 return this.el.select('input.hidden-number-input',true).first();
42625 * @class Roo.bootstrap.BezierSignature
42626 * @extends Roo.bootstrap.Component
42627 * Bootstrap BezierSignature class
42628 * This script refer to:
42629 * Title: Signature Pad
42631 * Availability: https://github.com/szimek/signature_pad
42634 * Create a new BezierSignature
42635 * @param {Object} config The config object
42638 Roo.bootstrap.BezierSignature = function(config){
42639 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
42645 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
42652 mouse_btn_down: true,
42655 * @cfg {int} canvas height
42657 canvas_height: '200px',
42660 * @cfg {float|function} Radius of a single dot.
42665 * @cfg {float} Minimum width of a line. Defaults to 0.5.
42670 * @cfg {float} Maximum width of a line. Defaults to 2.5.
42675 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
42680 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
42685 * @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.
42687 bg_color: 'rgba(0, 0, 0, 0)',
42690 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
42692 dot_color: 'black',
42695 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
42697 velocity_filter_weight: 0.7,
42700 * @cfg {function} Callback when stroke begin.
42705 * @cfg {function} Callback when stroke end.
42709 getAutoCreate : function()
42711 var cls = 'roo-signature column';
42714 cls += ' ' + this.cls;
42724 for(var i = 0; i < col_sizes.length; i++) {
42725 if(this[col_sizes[i]]) {
42726 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
42736 cls: 'roo-signature-body',
42740 cls: 'roo-signature-body-canvas',
42741 height: this.canvas_height,
42742 width: this.canvas_width
42749 style: 'display: none'
42757 initEvents: function()
42759 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
42761 var canvas = this.canvasEl();
42763 // mouse && touch event swapping...
42764 canvas.dom.style.touchAction = 'none';
42765 canvas.dom.style.msTouchAction = 'none';
42767 this.mouse_btn_down = false;
42768 canvas.on('mousedown', this._handleMouseDown, this);
42769 canvas.on('mousemove', this._handleMouseMove, this);
42770 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
42772 if (window.PointerEvent) {
42773 canvas.on('pointerdown', this._handleMouseDown, this);
42774 canvas.on('pointermove', this._handleMouseMove, this);
42775 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
42778 if ('ontouchstart' in window) {
42779 canvas.on('touchstart', this._handleTouchStart, this);
42780 canvas.on('touchmove', this._handleTouchMove, this);
42781 canvas.on('touchend', this._handleTouchEnd, this);
42784 Roo.EventManager.onWindowResize(this.resize, this, true);
42786 // file input event
42787 this.fileEl().on('change', this.uploadImage, this);
42794 resize: function(){
42796 var canvas = this.canvasEl().dom;
42797 var ctx = this.canvasElCtx();
42798 var img_data = false;
42800 if(canvas.width > 0) {
42801 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
42803 // setting canvas width will clean img data
42806 var style = window.getComputedStyle ?
42807 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
42809 var padding_left = parseInt(style.paddingLeft) || 0;
42810 var padding_right = parseInt(style.paddingRight) || 0;
42812 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
42815 ctx.putImageData(img_data, 0, 0);
42819 _handleMouseDown: function(e)
42821 if (e.browserEvent.which === 1) {
42822 this.mouse_btn_down = true;
42823 this.strokeBegin(e);
42827 _handleMouseMove: function (e)
42829 if (this.mouse_btn_down) {
42830 this.strokeMoveUpdate(e);
42834 _handleMouseUp: function (e)
42836 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
42837 this.mouse_btn_down = false;
42842 _handleTouchStart: function (e) {
42844 e.preventDefault();
42845 if (e.browserEvent.targetTouches.length === 1) {
42846 // var touch = e.browserEvent.changedTouches[0];
42847 // this.strokeBegin(touch);
42849 this.strokeBegin(e); // assume e catching the correct xy...
42853 _handleTouchMove: function (e) {
42854 e.preventDefault();
42855 // var touch = event.targetTouches[0];
42856 // _this._strokeMoveUpdate(touch);
42857 this.strokeMoveUpdate(e);
42860 _handleTouchEnd: function (e) {
42861 var wasCanvasTouched = e.target === this.canvasEl().dom;
42862 if (wasCanvasTouched) {
42863 e.preventDefault();
42864 // var touch = event.changedTouches[0];
42865 // _this._strokeEnd(touch);
42870 reset: function () {
42871 this._lastPoints = [];
42872 this._lastVelocity = 0;
42873 this._lastWidth = (this.min_width + this.max_width) / 2;
42874 this.canvasElCtx().fillStyle = this.dot_color;
42877 strokeMoveUpdate: function(e)
42879 this.strokeUpdate(e);
42881 if (this.throttle) {
42882 this.throttleStroke(this.strokeUpdate, this.throttle);
42885 this.strokeUpdate(e);
42889 strokeBegin: function(e)
42891 var newPointGroup = {
42892 color: this.dot_color,
42896 if (typeof this.onBegin === 'function') {
42900 this.curve_data.push(newPointGroup);
42902 this.strokeUpdate(e);
42905 strokeUpdate: function(e)
42907 var rect = this.canvasEl().dom.getBoundingClientRect();
42908 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
42909 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
42910 var lastPoints = lastPointGroup.points;
42911 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
42912 var isLastPointTooClose = lastPoint
42913 ? point.distanceTo(lastPoint) <= this.min_distance
42915 var color = lastPointGroup.color;
42916 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
42917 var curve = this.addPoint(point);
42919 this.drawDot({color: color, point: point});
42922 this.drawCurve({color: color, curve: curve});
42932 strokeEnd: function(e)
42934 this.strokeUpdate(e);
42935 if (typeof this.onEnd === 'function') {
42940 addPoint: function (point) {
42941 var _lastPoints = this._lastPoints;
42942 _lastPoints.push(point);
42943 if (_lastPoints.length > 2) {
42944 if (_lastPoints.length === 3) {
42945 _lastPoints.unshift(_lastPoints[0]);
42947 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
42948 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
42949 _lastPoints.shift();
42955 calculateCurveWidths: function (startPoint, endPoint) {
42956 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
42957 (1 - this.velocity_filter_weight) * this._lastVelocity;
42959 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
42962 start: this._lastWidth
42965 this._lastVelocity = velocity;
42966 this._lastWidth = newWidth;
42970 drawDot: function (_a) {
42971 var color = _a.color, point = _a.point;
42972 var ctx = this.canvasElCtx();
42973 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
42975 this.drawCurveSegment(point.x, point.y, width);
42977 ctx.fillStyle = color;
42981 drawCurve: function (_a) {
42982 var color = _a.color, curve = _a.curve;
42983 var ctx = this.canvasElCtx();
42984 var widthDelta = curve.endWidth - curve.startWidth;
42985 var drawSteps = Math.floor(curve.length()) * 2;
42987 ctx.fillStyle = color;
42988 for (var i = 0; i < drawSteps; i += 1) {
42989 var t = i / drawSteps;
42995 var x = uuu * curve.startPoint.x;
42996 x += 3 * uu * t * curve.control1.x;
42997 x += 3 * u * tt * curve.control2.x;
42998 x += ttt * curve.endPoint.x;
42999 var y = uuu * curve.startPoint.y;
43000 y += 3 * uu * t * curve.control1.y;
43001 y += 3 * u * tt * curve.control2.y;
43002 y += ttt * curve.endPoint.y;
43003 var width = curve.startWidth + ttt * widthDelta;
43004 this.drawCurveSegment(x, y, width);
43010 drawCurveSegment: function (x, y, width) {
43011 var ctx = this.canvasElCtx();
43013 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
43014 this.is_empty = false;
43019 var ctx = this.canvasElCtx();
43020 var canvas = this.canvasEl().dom;
43021 ctx.fillStyle = this.bg_color;
43022 ctx.clearRect(0, 0, canvas.width, canvas.height);
43023 ctx.fillRect(0, 0, canvas.width, canvas.height);
43024 this.curve_data = [];
43026 this.is_empty = true;
43031 return this.el.select('input',true).first();
43034 canvasEl: function()
43036 return this.el.select('canvas',true).first();
43039 canvasElCtx: function()
43041 return this.el.select('canvas',true).first().dom.getContext('2d');
43044 getImage: function(type)
43046 if(this.is_empty) {
43051 return this.canvasEl().dom.toDataURL('image/'+type, 1);
43054 drawFromImage: function(img_src)
43056 var img = new Image();
43058 img.onload = function(){
43059 this.canvasElCtx().drawImage(img, 0, 0);
43064 this.is_empty = false;
43067 selectImage: function()
43069 this.fileEl().dom.click();
43072 uploadImage: function(e)
43074 var reader = new FileReader();
43076 reader.onload = function(e){
43077 var img = new Image();
43078 img.onload = function(){
43080 this.canvasElCtx().drawImage(img, 0, 0);
43082 img.src = e.target.result;
43085 reader.readAsDataURL(e.target.files[0]);
43088 // Bezier Point Constructor
43089 Point: (function () {
43090 function Point(x, y, time) {
43093 this.time = time || Date.now();
43095 Point.prototype.distanceTo = function (start) {
43096 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
43098 Point.prototype.equals = function (other) {
43099 return this.x === other.x && this.y === other.y && this.time === other.time;
43101 Point.prototype.velocityFrom = function (start) {
43102 return this.time !== start.time
43103 ? this.distanceTo(start) / (this.time - start.time)
43110 // Bezier Constructor
43111 Bezier: (function () {
43112 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
43113 this.startPoint = startPoint;
43114 this.control2 = control2;
43115 this.control1 = control1;
43116 this.endPoint = endPoint;
43117 this.startWidth = startWidth;
43118 this.endWidth = endWidth;
43120 Bezier.fromPoints = function (points, widths, scope) {
43121 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
43122 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
43123 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
43125 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
43126 var dx1 = s1.x - s2.x;
43127 var dy1 = s1.y - s2.y;
43128 var dx2 = s2.x - s3.x;
43129 var dy2 = s2.y - s3.y;
43130 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
43131 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
43132 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
43133 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
43134 var dxm = m1.x - m2.x;
43135 var dym = m1.y - m2.y;
43136 var k = l2 / (l1 + l2);
43137 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
43138 var tx = s2.x - cm.x;
43139 var ty = s2.y - cm.y;
43141 c1: new scope.Point(m1.x + tx, m1.y + ty),
43142 c2: new scope.Point(m2.x + tx, m2.y + ty)
43145 Bezier.prototype.length = function () {
43150 for (var i = 0; i <= steps; i += 1) {
43152 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
43153 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
43155 var xdiff = cx - px;
43156 var ydiff = cy - py;
43157 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
43164 Bezier.prototype.point = function (t, start, c1, c2, end) {
43165 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
43166 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
43167 + (3.0 * c2 * (1.0 - t) * t * t)
43168 + (end * t * t * t);
43173 throttleStroke: function(fn, wait) {
43174 if (wait === void 0) { wait = 250; }
43176 var timeout = null;
43180 var later = function () {
43181 previous = Date.now();
43183 result = fn.apply(storedContext, storedArgs);
43185 storedContext = null;
43189 return function wrapper() {
43191 for (var _i = 0; _i < arguments.length; _i++) {
43192 args[_i] = arguments[_i];
43194 var now = Date.now();
43195 var remaining = wait - (now - previous);
43196 storedContext = this;
43198 if (remaining <= 0 || remaining > wait) {
43200 clearTimeout(timeout);
43204 result = fn.apply(storedContext, storedArgs);
43206 storedContext = null;
43210 else if (!timeout) {
43211 timeout = window.setTimeout(later, remaining);