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.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
61 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
64 allowDomMove : false, // to stop relocations in parent onRender...
74 * Initialize Events for the element
76 initEvents : function() { },
82 can_build_overlaid : true,
84 container_method : false,
91 // returns the parent component..
92 return Roo.ComponentMgr.get(this.parentId)
98 onRender : function(ct, position)
100 // Roo.log("Call onRender: " + this.xtype);
102 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
105 if (this.el.attr('xtype')) {
106 this.el.attr('xtypex', this.el.attr('xtype'));
107 this.el.dom.removeAttribute('xtype');
117 var cfg = Roo.apply({}, this.getAutoCreate());
119 cfg.id = this.id || Roo.id();
121 // fill in the extra attributes
122 if (this.xattr && typeof(this.xattr) =='object') {
123 for (var i in this.xattr) {
124 cfg[i] = this.xattr[i];
129 cfg.dataId = this.dataId;
133 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
136 if (this.style) { // fixme needs to support more complex style data.
137 cfg.style = this.style;
141 cfg.name = this.name;
144 this.el = ct.createChild(cfg, position);
147 this.tooltipEl().attr('tooltip', this.tooltip);
150 if(this.tabIndex !== undefined){
151 this.el.dom.setAttribute('tabIndex', this.tabIndex);
158 * Fetch the element to add children to
159 * @return {Roo.Element} defaults to this.el
161 getChildContainer : function()
166 * Fetch the element to display the tooltip on.
167 * @return {Roo.Element} defaults to this.el
169 tooltipEl : function()
174 * This is really a wrapper for addxtypeChild
175 * it handles stuff relating to flexy:foreach / flexy:if
176 * = some of our projects use a flat rendering of the output, and try and overlay it with dynamic data.
177 * -- this is a bit of a nightmare... and is even more confusing to debug..
182 addxtype : function(tree,cntr)
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 var cn = Roo.factory(tree); // this is posibly the first of two times that the ctor get's called...
187 cn.parentType = this.xtype; //??
188 cn.parentId = this.id;
189 if (typeof(cn.container_method) == 'string') {
190 cntr = cn.container_method;
194 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
196 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
198 var build_from_html = Roo.XComponent.build_from_html;
200 var is_body = (tree.xtype == 'Body') ;
202 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
204 var self_cntr_el = Roo.get(this[cntr](false));
206 // do not try and build conditional elements
207 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
211 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
212 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
213 //return this.addxtypeChild(tree,cntr, is_body);
214 return this.addxtypeChild(tree, cntr, is_body);
217 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
220 return this.addxtypeChild(Roo.apply({}, tree),cntr);
223 Roo.log('skipping render');
229 if (!build_from_html) {
233 // this i think handles overlaying multiple children of the same type
234 // with the sam eelement.. - which might be buggy..
236 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
242 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
246 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
252 * add a child to this element
253 * - turn the child.cfg into a child_instance
254 * - call child_instance.render( this { getContainerMethod()} )
255 * - loop through the children, and call addxtype.. (reall this) on newly created child.
259 addxtypeChild : function (tree, cntr, is_body)
261 Roo.debug && Roo.log('addxtypeChild:' + cntr);
263 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
266 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
267 (typeof(tree['flexy:foreach']) != 'undefined');
271 skip_children = false;
272 // render the element if it's not BODY.
275 // if parent was disabled, then do not try and create the children..
276 if(!this[cntr](true)){
281 cn = Roo.factory(tree);
283 cn.parentType = this.xtype; //??
284 cn.parentId = this.id;
286 var build_from_html = Roo.XComponent.build_from_html;
289 // does the container contain child eleemnts with 'xtype' attributes.
290 // that match this xtype..
291 // note - when we render we create these as well..
292 // so we should check to see if body has xtype set.
293 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
295 var self_cntr_el = Roo.get(this[cntr](false));
296 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
298 //Roo.log(Roo.XComponent.build_from_html);
299 //Roo.log("got echild:");
302 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
303 // and are not displayed -this causes this to use up the wrong element when matching.
304 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
307 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
308 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
314 //echild.dom.removeAttribute('xtype');
316 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
317 Roo.debug && Roo.log(self_cntr_el);
318 Roo.debug && Roo.log(echild);
319 Roo.debug && Roo.log(cn);
325 // if object has flexy:if - then it may or may not be rendered.
326 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
327 // skip a flexy if element.
328 Roo.debug && Roo.log('skipping render');
329 Roo.debug && Roo.log(tree);
331 Roo.debug && Roo.log('skipping all children');
332 skip_children = true;
337 // actually if flexy:foreach is found, we really want to create
338 // multiple copies here...
340 //Roo.log(this[cntr]());
341 // some elements do not have render methods.. like the layouts...
343 if(this[cntr](true) === false){
348 cn.render && cn.render(this[cntr](true));
351 // then add the element..
358 cn.addxtypeChildren(tree.items, skip_children);
364 * add a number of children to this object,
365 * which in turn calls render...
369 addxtypeChildren: function(child_array, skip_children)
372 if (!child_array || !child_array.length ) {
377 for(var i =0;i < child_array.length;i++) {
381 // Roo.log(['add child', items[i]]);
382 nitems.push(this.addxtype(Roo.apply({}, child_array[i])));
386 this.fireEvent('childrenrendered', this);
393 * Set the element that will be used to show or hide
395 setVisibilityEl : function(el)
397 this.visibilityEl = el;
401 * Get the element that will be used to show or hide
403 getVisibilityEl : function()
405 if (typeof(this.visibilityEl) == 'object') {
406 return this.visibilityEl;
409 if (typeof(this.visibilityEl) == 'string') {
410 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
417 * Show a component - removes 'hidden' class
421 if(!this.getVisibilityEl()){
425 this.getVisibilityEl().removeClass(['hidden','d-none']);
427 this.fireEvent('show', this);
432 * Hide a component - adds 'hidden' class
436 if(!this.getVisibilityEl()){
440 this.getVisibilityEl().addClass(['hidden','d-none']);
442 this.fireEvent('hide', this);
455 * @class Roo.bootstrap.Body
456 * @extends Roo.bootstrap.Component
457 * Bootstrap Body class
461 * @param {Object} config The config object
462 * @cfg {DomElement} do_render - if this is set, then the constructor will try and initialize render, using this as the start point
466 Roo.bootstrap.Body = function(config){
468 config = config || {};
470 Roo.bootstrap.Body.superclass.constructor.call(this, config);
471 this.el = Roo.get(config.el ? config.el : document.body );
472 if (this.cls && this.cls.length) {
473 Roo.get(document.body).addClass(this.cls);
475 if (config.do_render) {
476 this.onRender(config.do_render, '');
477 this.xAddChildren(config.items);
482 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
485 is_body : true,// just to make sure it's constructed?
490 onRender : function(ct, position)
492 if (!this.do_render) {
495 this.el = Roo.get(this.do_render);
496 /* Roo.log("Roo.bootstrap.Body - onRender");
497 if (this.cls && this.cls.length) {
498 Roo.get(document.body).addClass(this.cls);
517 * @class Roo.bootstrap.ButtonGroup
518 * @extends Roo.bootstrap.Component
519 * Bootstrap ButtonGroup class
520 * @cfg {String} size lg | sm | xs (default empty normal)
521 * @cfg {String} align vertical | justified (default none)
522 * @cfg {String} direction up | down (default down)
523 * @cfg {Boolean} toolbar false | true
524 * @cfg {Boolean} btn true | false
529 * @param {Object} config The config object
532 Roo.bootstrap.ButtonGroup = function(config){
533 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
536 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
544 getAutoCreate : function(){
550 cfg.html = this.html || cfg.html;
561 if (['vertical','justified'].indexOf(this.align)!==-1) {
562 cfg.cls = 'btn-group-' + this.align;
564 if (this.align == 'justified') {
565 console.log(this.items);
569 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
570 cfg.cls += ' btn-group-' + this.size;
573 if (this.direction == 'up') {
574 cfg.cls += ' dropup' ;
580 * Add a button to the group (similar to NavItem API.)
582 addItem : function(cfg)
584 var cn = new Roo.bootstrap.Button(cfg);
586 cn.parentId = this.id;
587 cn.onRender(this.el, null);
601 * @class Roo.bootstrap.Button
602 * @extends Roo.bootstrap.Component
603 * Bootstrap Button class
604 * @cfg {String} html The button content
605 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
606 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
607 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
608 * @cfg {String} size ( lg | sm | xs)
609 * @cfg {String} tag ( a | input | submit)
610 * @cfg {String} href empty or href
611 * @cfg {Boolean} disabled default false;
612 * @cfg {Boolean} isClose default false;
613 * @cfg {String} glyphicon depricated - use fa
614 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
615 * @cfg {String} badge text for badge
616 * @cfg {String} theme (default|glow)
617 * @cfg {Boolean} inverse dark themed version
618 * @cfg {Boolean} toggle is it a slidy toggle button
619 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
620 * @cfg {String} ontext text for on slidy toggle state
621 * @cfg {String} offtext text for off slidy toggle state
622 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
623 * @cfg {Boolean} removeClass remove the standard class..
624 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
627 * Create a new button
628 * @param {Object} config The config object
632 Roo.bootstrap.Button = function(config){
633 Roo.bootstrap.Button.superclass.constructor.call(this, config);
634 this.weightClass = ["btn-default btn-outline-secondary",
646 * When a butotn is pressed
647 * @param {Roo.bootstrap.Button} btn
648 * @param {Roo.EventObject} e
653 * After the button has been toggles
654 * @param {Roo.bootstrap.Button} btn
655 * @param {Roo.EventObject} e
656 * @param {boolean} pressed (also available as button.pressed)
662 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
683 preventDefault: true,
691 getAutoCreate : function(){
699 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
700 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
705 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
707 if (this.toggle == true) {
710 cls: 'slider-frame roo-button',
715 'data-off-text':'OFF',
716 cls: 'slider-button',
722 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
723 cfg.cls += ' '+this.weight;
732 cfg["aria-hidden"] = true;
734 cfg.html = "×";
740 if (this.theme==='default') {
741 cfg.cls = 'btn roo-button';
743 //if (this.parentType != 'Navbar') {
744 this.weight = this.weight.length ? this.weight : 'default';
746 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
748 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
749 var weight = this.weight == 'default' ? 'secondary' : this.weight;
750 cfg.cls += ' btn-' + outline + weight;
751 if (this.weight == 'default') {
753 cfg.cls += ' btn-' + this.weight;
756 } else if (this.theme==='glow') {
759 cfg.cls = 'btn-glow roo-button';
761 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
763 cfg.cls += ' ' + this.weight;
769 this.cls += ' inverse';
773 if (this.active || this.pressed === true) {
774 cfg.cls += ' active';
778 cfg.disabled = 'disabled';
782 Roo.log('changing to ul' );
784 this.glyphicon = 'caret';
785 if (Roo.bootstrap.version == 4) {
786 this.fa = 'caret-down';
791 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
793 //gsRoo.log(this.parentType);
794 if (this.parentType === 'Navbar' && !this.parent().bar) {
795 Roo.log('changing to li?');
804 href : this.href || '#'
807 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
808 cfg.cls += ' dropdown';
815 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
817 if (this.glyphicon) {
818 cfg.html = ' ' + cfg.html;
823 cls: 'glyphicon glyphicon-' + this.glyphicon
828 cfg.html = ' ' + cfg.html;
833 cls: 'fa fas fa-' + this.fa
843 // cfg.cls='btn roo-button';
847 var value = cfg.html;
852 cls: 'glyphicon glyphicon-' + this.glyphicon,
859 cls: 'fa fas fa-' + this.fa,
864 var bw = this.badge_weight.length ? this.badge_weight :
865 (this.weight.length ? this.weight : 'secondary');
866 bw = bw == 'default' ? 'secondary' : bw;
872 cls: 'badge badge-' + bw,
881 cfg.cls += ' dropdown';
882 cfg.html = typeof(cfg.html) != 'undefined' ?
883 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
886 if (cfg.tag !== 'a' && this.href !== '') {
887 throw "Tag must be a to set href.";
888 } else if (this.href.length > 0) {
889 cfg.href = this.href;
892 if(this.removeClass){
897 cfg.target = this.target;
902 initEvents: function() {
903 // Roo.log('init events?');
904 // Roo.log(this.el.dom);
907 if (typeof (this.menu) != 'undefined') {
908 this.menu.parentType = this.xtype;
909 this.menu.triggerEl = this.el;
910 this.addxtype(Roo.apply({}, this.menu));
914 if (this.el.hasClass('roo-button')) {
915 this.el.on('click', this.onClick, this);
917 this.el.select('.roo-button').on('click', this.onClick, this);
920 if(this.removeClass){
921 this.el.on('click', this.onClick, this);
924 this.el.enableDisplayMode();
927 onClick : function(e)
933 Roo.log('button on click ');
934 if(this.preventDefault){
938 if (this.pressed === true || this.pressed === false) {
939 this.toggleActive(e);
943 this.fireEvent('click', this, e);
947 * Enables this button
951 this.disabled = false;
952 this.el.removeClass('disabled');
956 * Disable this button
960 this.disabled = true;
961 this.el.addClass('disabled');
964 * sets the active state on/off,
965 * @param {Boolean} state (optional) Force a particular state
967 setActive : function(v) {
969 this.el[v ? 'addClass' : 'removeClass']('active');
973 * toggles the current active state
975 toggleActive : function(e)
977 this.setActive(!this.pressed);
978 this.fireEvent('toggle', this, e, !this.pressed);
981 * get the current active state
982 * @return {boolean} true if it's active
984 isActive : function()
986 return this.el.hasClass('active');
989 * set the text of the first selected button
991 setText : function(str)
993 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
996 * get the text of the first selected button
1000 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
1003 setWeight : function(str)
1005 this.el.removeClass(this.weightClass);
1007 var outline = this.outline ? 'outline-' : '';
1008 if (str == 'default') {
1009 this.el.addClass('btn-default btn-outline-secondary');
1012 this.el.addClass('btn-' + outline + str);
1026 * @class Roo.bootstrap.Column
1027 * @extends Roo.bootstrap.Component
1028 * Bootstrap Column class
1029 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1030 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1031 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1032 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1033 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1034 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1035 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1036 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1039 * @cfg {Boolean} hidden (true|false) hide the element
1040 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1041 * @cfg {String} fa (ban|check|...) font awesome icon
1042 * @cfg {Number} fasize (1|2|....) font awsome size
1044 * @cfg {String} icon (info-sign|check|...) glyphicon name
1046 * @cfg {String} html content of column.
1049 * Create a new Column
1050 * @param {Object} config The config object
1053 Roo.bootstrap.Column = function(config){
1054 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1057 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1075 getAutoCreate : function(){
1076 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1084 ['xs','sm','md','lg'].map(function(size){
1085 //Roo.log( size + ':' + settings[size]);
1087 if (settings[size+'off'] !== false) {
1088 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1091 if (settings[size] === false) {
1095 if (!settings[size]) { // 0 = hidden
1096 cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
1099 cfg.cls += ' col-' + size + '-' + settings[size] + (
1100 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1106 cfg.cls += ' hidden';
1109 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1110 cfg.cls +=' alert alert-' + this.alert;
1114 if (this.html.length) {
1115 cfg.html = this.html;
1119 if (this.fasize > 1) {
1120 fasize = ' fa-' + this.fasize + 'x';
1122 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1127 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1146 * @class Roo.bootstrap.Container
1147 * @extends Roo.bootstrap.Component
1148 * Bootstrap Container class
1149 * @cfg {Boolean} jumbotron is it a jumbotron element
1150 * @cfg {String} html content of element
1151 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1152 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1153 * @cfg {String} header content of header (for panel)
1154 * @cfg {String} footer content of footer (for panel)
1155 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1156 * @cfg {String} tag (header|aside|section) type of HTML tag.
1157 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1158 * @cfg {String} fa font awesome icon
1159 * @cfg {String} icon (info-sign|check|...) glyphicon name
1160 * @cfg {Boolean} hidden (true|false) hide the element
1161 * @cfg {Boolean} expandable (true|false) default false
1162 * @cfg {Boolean} expanded (true|false) default true
1163 * @cfg {String} rheader contet on the right of header
1164 * @cfg {Boolean} clickable (true|false) default false
1168 * Create a new Container
1169 * @param {Object} config The config object
1172 Roo.bootstrap.Container = function(config){
1173 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1179 * After the panel has been expand
1181 * @param {Roo.bootstrap.Container} this
1186 * After the panel has been collapsed
1188 * @param {Roo.bootstrap.Container} this
1193 * When a element is chick
1194 * @param {Roo.bootstrap.Container} this
1195 * @param {Roo.EventObject} e
1201 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1219 getChildContainer : function() {
1225 if (this.panel.length) {
1226 return this.el.select('.panel-body',true).first();
1233 getAutoCreate : function(){
1236 tag : this.tag || 'div',
1240 if (this.jumbotron) {
1241 cfg.cls = 'jumbotron';
1246 // - this is applied by the parent..
1248 // cfg.cls = this.cls + '';
1251 if (this.sticky.length) {
1253 var bd = Roo.get(document.body);
1254 if (!bd.hasClass('bootstrap-sticky')) {
1255 bd.addClass('bootstrap-sticky');
1256 Roo.select('html',true).setStyle('height', '100%');
1259 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1263 if (this.well.length) {
1264 switch (this.well) {
1267 cfg.cls +=' well well-' +this.well;
1276 cfg.cls += ' hidden';
1280 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1281 cfg.cls +=' alert alert-' + this.alert;
1286 if (this.panel.length) {
1287 cfg.cls += ' panel panel-' + this.panel;
1289 if (this.header.length) {
1293 if(this.expandable){
1295 cfg.cls = cfg.cls + ' expandable';
1299 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1307 cls : 'panel-title',
1308 html : (this.expandable ? ' ' : '') + this.header
1312 cls: 'panel-header-right',
1318 cls : 'panel-heading',
1319 style : this.expandable ? 'cursor: pointer' : '',
1327 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1332 if (this.footer.length) {
1334 cls : 'panel-footer',
1343 body.html = this.html || cfg.html;
1344 // prefix with the icons..
1346 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1349 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1354 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1355 cfg.cls = 'container';
1361 initEvents: function()
1363 if(this.expandable){
1364 var headerEl = this.headerEl();
1367 headerEl.on('click', this.onToggleClick, this);
1372 this.el.on('click', this.onClick, this);
1377 onToggleClick : function()
1379 var headerEl = this.headerEl();
1395 if(this.fireEvent('expand', this)) {
1397 this.expanded = true;
1399 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1401 this.el.select('.panel-body',true).first().removeClass('hide');
1403 var toggleEl = this.toggleEl();
1409 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1414 collapse : function()
1416 if(this.fireEvent('collapse', this)) {
1418 this.expanded = false;
1420 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1421 this.el.select('.panel-body',true).first().addClass('hide');
1423 var toggleEl = this.toggleEl();
1429 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1433 toggleEl : function()
1435 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1439 return this.el.select('.panel-heading .fa',true).first();
1442 headerEl : function()
1444 if(!this.el || !this.panel.length || !this.header.length){
1448 return this.el.select('.panel-heading',true).first()
1453 if(!this.el || !this.panel.length){
1457 return this.el.select('.panel-body',true).first()
1460 titleEl : function()
1462 if(!this.el || !this.panel.length || !this.header.length){
1466 return this.el.select('.panel-title',true).first();
1469 setTitle : function(v)
1471 var titleEl = this.titleEl();
1477 titleEl.dom.innerHTML = v;
1480 getTitle : function()
1483 var titleEl = this.titleEl();
1489 return titleEl.dom.innerHTML;
1492 setRightTitle : function(v)
1494 var t = this.el.select('.panel-header-right',true).first();
1500 t.dom.innerHTML = v;
1503 onClick : function(e)
1507 this.fireEvent('click', this, e);
1520 * @class Roo.bootstrap.Img
1521 * @extends Roo.bootstrap.Component
1522 * Bootstrap Img class
1523 * @cfg {Boolean} imgResponsive false | true
1524 * @cfg {String} border rounded | circle | thumbnail
1525 * @cfg {String} src image source
1526 * @cfg {String} alt image alternative text
1527 * @cfg {String} href a tag href
1528 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1529 * @cfg {String} xsUrl xs image source
1530 * @cfg {String} smUrl sm image source
1531 * @cfg {String} mdUrl md image source
1532 * @cfg {String} lgUrl lg image source
1535 * Create a new Input
1536 * @param {Object} config The config object
1539 Roo.bootstrap.Img = function(config){
1540 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1546 * The img click event for the img.
1547 * @param {Roo.EventObject} e
1553 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1555 imgResponsive: true,
1565 getAutoCreate : function()
1567 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1568 return this.createSingleImg();
1573 cls: 'roo-image-responsive-group',
1578 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1580 if(!_this[size + 'Url']){
1586 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1587 html: _this.html || cfg.html,
1588 src: _this[size + 'Url']
1591 img.cls += ' roo-image-responsive-' + size;
1593 var s = ['xs', 'sm', 'md', 'lg'];
1595 s.splice(s.indexOf(size), 1);
1597 Roo.each(s, function(ss){
1598 img.cls += ' hidden-' + ss;
1601 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1602 cfg.cls += ' img-' + _this.border;
1606 cfg.alt = _this.alt;
1619 a.target = _this.target;
1623 cfg.cn.push((_this.href) ? a : img);
1630 createSingleImg : function()
1634 cls: (this.imgResponsive) ? 'img-responsive' : '',
1636 src : 'about:blank' // just incase src get's set to undefined?!?
1639 cfg.html = this.html || cfg.html;
1641 cfg.src = this.src || cfg.src;
1643 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1644 cfg.cls += ' img-' + this.border;
1661 a.target = this.target;
1666 return (this.href) ? a : cfg;
1669 initEvents: function()
1672 this.el.on('click', this.onClick, this);
1677 onClick : function(e)
1679 Roo.log('img onclick');
1680 this.fireEvent('click', this, e);
1683 * Sets the url of the image - used to update it
1684 * @param {String} url the url of the image
1687 setSrc : function(url)
1691 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1692 this.el.dom.src = url;
1696 this.el.select('img', true).first().dom.src = url;
1712 * @class Roo.bootstrap.Link
1713 * @extends Roo.bootstrap.Component
1714 * Bootstrap Link Class
1715 * @cfg {String} alt image alternative text
1716 * @cfg {String} href a tag href
1717 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1718 * @cfg {String} html the content of the link.
1719 * @cfg {String} anchor name for the anchor link
1720 * @cfg {String} fa - favicon
1722 * @cfg {Boolean} preventDefault (true | false) default false
1726 * Create a new Input
1727 * @param {Object} config The config object
1730 Roo.bootstrap.Link = function(config){
1731 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1737 * The img click event for the img.
1738 * @param {Roo.EventObject} e
1744 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1748 preventDefault: false,
1754 getAutoCreate : function()
1756 var html = this.html || '';
1758 if (this.fa !== false) {
1759 html = '<i class="fa fa-' + this.fa + '"></i>';
1764 // anchor's do not require html/href...
1765 if (this.anchor === false) {
1767 cfg.href = this.href || '#';
1769 cfg.name = this.anchor;
1770 if (this.html !== false || this.fa !== false) {
1773 if (this.href !== false) {
1774 cfg.href = this.href;
1778 if(this.alt !== false){
1783 if(this.target !== false) {
1784 cfg.target = this.target;
1790 initEvents: function() {
1792 if(!this.href || this.preventDefault){
1793 this.el.on('click', this.onClick, this);
1797 onClick : function(e)
1799 if(this.preventDefault){
1802 //Roo.log('img onclick');
1803 this.fireEvent('click', this, e);
1816 * @class Roo.bootstrap.Header
1817 * @extends Roo.bootstrap.Component
1818 * Bootstrap Header class
1819 * @cfg {String} html content of header
1820 * @cfg {Number} level (1|2|3|4|5|6) default 1
1823 * Create a new Header
1824 * @param {Object} config The config object
1828 Roo.bootstrap.Header = function(config){
1829 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1832 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1840 getAutoCreate : function(){
1845 tag: 'h' + (1 *this.level),
1846 html: this.html || ''
1858 * Ext JS Library 1.1.1
1859 * Copyright(c) 2006-2007, Ext JS, LLC.
1861 * Originally Released Under LGPL - original licence link has changed is not relivant.
1864 * <script type="text/javascript">
1868 * @class Roo.bootstrap.MenuMgr
1869 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1872 Roo.bootstrap.MenuMgr = function(){
1873 var menus, active, groups = {}, attached = false, lastShow = new Date();
1875 // private - called when first menu is created
1878 active = new Roo.util.MixedCollection();
1879 Roo.get(document).addKeyListener(27, function(){
1880 if(active.length > 0){
1888 if(active && active.length > 0){
1889 var c = active.clone();
1899 if(active.length < 1){
1900 Roo.get(document).un("mouseup", onMouseDown);
1908 var last = active.last();
1909 lastShow = new Date();
1912 Roo.get(document).on("mouseup", onMouseDown);
1917 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1918 m.parentMenu.activeChild = m;
1919 }else if(last && last.isVisible()){
1920 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1925 function onBeforeHide(m){
1927 m.activeChild.hide();
1929 if(m.autoHideTimer){
1930 clearTimeout(m.autoHideTimer);
1931 delete m.autoHideTimer;
1936 function onBeforeShow(m){
1937 var pm = m.parentMenu;
1938 if(!pm && !m.allowOtherMenus){
1940 }else if(pm && pm.activeChild && active != m){
1941 pm.activeChild.hide();
1945 // private this should really trigger on mouseup..
1946 function onMouseDown(e){
1947 Roo.log("on Mouse Up");
1949 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1950 Roo.log("MenuManager hideAll");
1959 function onBeforeCheck(mi, state){
1961 var g = groups[mi.group];
1962 for(var i = 0, l = g.length; i < l; i++){
1964 g[i].setChecked(false);
1973 * Hides all menus that are currently visible
1975 hideAll : function(){
1980 register : function(menu){
1984 menus[menu.id] = menu;
1985 menu.on("beforehide", onBeforeHide);
1986 menu.on("hide", onHide);
1987 menu.on("beforeshow", onBeforeShow);
1988 menu.on("show", onShow);
1990 if(g && menu.events["checkchange"]){
1994 groups[g].push(menu);
1995 menu.on("checkchange", onCheck);
2000 * Returns a {@link Roo.menu.Menu} object
2001 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
2002 * be used to generate and return a new Menu instance.
2004 get : function(menu){
2005 if(typeof menu == "string"){ // menu id
2007 }else if(menu.events){ // menu instance
2010 /*else if(typeof menu.length == 'number'){ // array of menu items?
2011 return new Roo.bootstrap.Menu({items:menu});
2012 }else{ // otherwise, must be a config
2013 return new Roo.bootstrap.Menu(menu);
2020 unregister : function(menu){
2021 delete menus[menu.id];
2022 menu.un("beforehide", onBeforeHide);
2023 menu.un("hide", onHide);
2024 menu.un("beforeshow", onBeforeShow);
2025 menu.un("show", onShow);
2027 if(g && menu.events["checkchange"]){
2028 groups[g].remove(menu);
2029 menu.un("checkchange", onCheck);
2034 registerCheckable : function(menuItem){
2035 var g = menuItem.group;
2040 groups[g].push(menuItem);
2041 menuItem.on("beforecheckchange", onBeforeCheck);
2046 unregisterCheckable : function(menuItem){
2047 var g = menuItem.group;
2049 groups[g].remove(menuItem);
2050 menuItem.un("beforecheckchange", onBeforeCheck);
2062 * @class Roo.bootstrap.Menu
2063 * @extends Roo.bootstrap.Component
2064 * Bootstrap Menu class - container for MenuItems
2065 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2066 * @cfg {bool} hidden if the menu should be hidden when rendered.
2067 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2068 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2072 * @param {Object} config The config object
2076 Roo.bootstrap.Menu = function(config){
2077 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2078 if (this.registerMenu && this.type != 'treeview') {
2079 Roo.bootstrap.MenuMgr.register(this);
2086 * Fires before this menu is displayed (return false to block)
2087 * @param {Roo.menu.Menu} this
2092 * Fires before this menu is hidden (return false to block)
2093 * @param {Roo.menu.Menu} this
2098 * Fires after this menu is displayed
2099 * @param {Roo.menu.Menu} this
2104 * Fires after this menu is hidden
2105 * @param {Roo.menu.Menu} this
2110 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2111 * @param {Roo.menu.Menu} this
2112 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2113 * @param {Roo.EventObject} e
2118 * Fires when the mouse is hovering over this menu
2119 * @param {Roo.menu.Menu} this
2120 * @param {Roo.EventObject} e
2121 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2126 * Fires when the mouse exits this menu
2127 * @param {Roo.menu.Menu} this
2128 * @param {Roo.EventObject} e
2129 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2134 * Fires when a menu item contained in this menu is clicked
2135 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2136 * @param {Roo.EventObject} e
2140 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2143 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2147 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2150 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2152 registerMenu : true,
2154 menuItems :false, // stores the menu items..
2164 getChildContainer : function() {
2168 getAutoCreate : function(){
2170 //if (['right'].indexOf(this.align)!==-1) {
2171 // cfg.cn[1].cls += ' pull-right'
2177 cls : 'dropdown-menu' ,
2178 style : 'z-index:1000'
2182 if (this.type === 'submenu') {
2183 cfg.cls = 'submenu active';
2185 if (this.type === 'treeview') {
2186 cfg.cls = 'treeview-menu';
2191 initEvents : function() {
2193 // Roo.log("ADD event");
2194 // Roo.log(this.triggerEl.dom);
2196 this.triggerEl.on('click', this.onTriggerClick, this);
2198 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2201 if (this.triggerEl.hasClass('nav-item')) {
2202 // dropdown toggle on the 'a' in BS4?
2203 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2205 this.triggerEl.addClass('dropdown-toggle');
2208 this.el.on('touchstart' , this.onTouch, this);
2210 this.el.on('click' , this.onClick, this);
2212 this.el.on("mouseover", this.onMouseOver, this);
2213 this.el.on("mouseout", this.onMouseOut, this);
2217 findTargetItem : function(e)
2219 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2223 //Roo.log(t); Roo.log(t.id);
2225 //Roo.log(this.menuitems);
2226 return this.menuitems.get(t.id);
2228 //return this.items.get(t.menuItemId);
2234 onTouch : function(e)
2236 Roo.log("menu.onTouch");
2237 //e.stopEvent(); this make the user popdown broken
2241 onClick : function(e)
2243 Roo.log("menu.onClick");
2245 var t = this.findTargetItem(e);
2246 if(!t || t.isContainer){
2251 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2252 if(t == this.activeItem && t.shouldDeactivate(e)){
2253 this.activeItem.deactivate();
2254 delete this.activeItem;
2258 this.setActiveItem(t, true);
2266 Roo.log('pass click event');
2270 this.fireEvent("click", this, t, e);
2274 if(!t.href.length || t.href == '#'){
2275 (function() { _this.hide(); }).defer(100);
2280 onMouseOver : function(e){
2281 var t = this.findTargetItem(e);
2284 // if(t.canActivate && !t.disabled){
2285 // this.setActiveItem(t, true);
2289 this.fireEvent("mouseover", this, e, t);
2291 isVisible : function(){
2292 return !this.hidden;
2294 onMouseOut : function(e){
2295 var t = this.findTargetItem(e);
2298 // if(t == this.activeItem && t.shouldDeactivate(e)){
2299 // this.activeItem.deactivate();
2300 // delete this.activeItem;
2303 this.fireEvent("mouseout", this, e, t);
2308 * Displays this menu relative to another element
2309 * @param {String/HTMLElement/Roo.Element} element The element to align to
2310 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2311 * the element (defaults to this.defaultAlign)
2312 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2314 show : function(el, pos, parentMenu)
2316 if (false === this.fireEvent("beforeshow", this)) {
2317 Roo.log("show canceled");
2320 this.parentMenu = parentMenu;
2325 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2328 * Displays this menu at a specific xy position
2329 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2330 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2332 showAt : function(xy, parentMenu, /* private: */_e){
2333 this.parentMenu = parentMenu;
2338 this.fireEvent("beforeshow", this);
2339 //xy = this.el.adjustForConstraints(xy);
2343 this.hideMenuItems();
2344 this.hidden = false;
2345 this.triggerEl.addClass('open');
2346 this.el.addClass('show');
2348 // reassign x when hitting right
2349 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2350 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2353 // reassign y when hitting bottom
2354 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2355 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2358 // but the list may align on trigger left or trigger top... should it be a properity?
2360 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2365 this.fireEvent("show", this);
2371 this.doFocus.defer(50, this);
2375 doFocus : function(){
2377 this.focusEl.focus();
2382 * Hides this menu and optionally all parent menus
2383 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2385 hide : function(deep)
2387 if (false === this.fireEvent("beforehide", this)) {
2388 Roo.log("hide canceled");
2391 this.hideMenuItems();
2392 if(this.el && this.isVisible()){
2394 if(this.activeItem){
2395 this.activeItem.deactivate();
2396 this.activeItem = null;
2398 this.triggerEl.removeClass('open');;
2399 this.el.removeClass('show');
2401 this.fireEvent("hide", this);
2403 if(deep === true && this.parentMenu){
2404 this.parentMenu.hide(true);
2408 onTriggerClick : function(e)
2410 Roo.log('trigger click');
2412 var target = e.getTarget();
2414 Roo.log(target.nodeName.toLowerCase());
2416 if(target.nodeName.toLowerCase() === 'i'){
2422 onTriggerPress : function(e)
2424 Roo.log('trigger press');
2425 //Roo.log(e.getTarget());
2426 // Roo.log(this.triggerEl.dom);
2428 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2429 var pel = Roo.get(e.getTarget());
2430 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2431 Roo.log('is treeview or dropdown?');
2435 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2439 if (this.isVisible()) {
2444 this.show(this.triggerEl, '?', false);
2447 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2454 hideMenuItems : function()
2456 Roo.log("hide Menu Items");
2461 this.el.select('.open',true).each(function(aa) {
2463 aa.removeClass('open');
2467 addxtypeChild : function (tree, cntr) {
2468 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2470 this.menuitems.add(comp);
2482 this.getEl().dom.innerHTML = '';
2483 this.menuitems.clear();
2497 * @class Roo.bootstrap.MenuItem
2498 * @extends Roo.bootstrap.Component
2499 * Bootstrap MenuItem class
2500 * @cfg {String} html the menu label
2501 * @cfg {String} href the link
2502 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2503 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2504 * @cfg {Boolean} active used on sidebars to highlight active itesm
2505 * @cfg {String} fa favicon to show on left of menu item.
2506 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2510 * Create a new MenuItem
2511 * @param {Object} config The config object
2515 Roo.bootstrap.MenuItem = function(config){
2516 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2521 * The raw click event for the entire grid.
2522 * @param {Roo.bootstrap.MenuItem} this
2523 * @param {Roo.EventObject} e
2529 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2533 preventDefault: false,
2534 isContainer : false,
2538 getAutoCreate : function(){
2540 if(this.isContainer){
2543 cls: 'dropdown-menu-item '
2553 cls : 'dropdown-item',
2558 if (this.fa !== false) {
2561 cls : 'fa fa-' + this.fa
2570 cls: 'dropdown-menu-item',
2573 if (this.parent().type == 'treeview') {
2574 cfg.cls = 'treeview-menu';
2577 cfg.cls += ' active';
2582 anc.href = this.href || cfg.cn[0].href ;
2583 ctag.html = this.html || cfg.cn[0].html ;
2587 initEvents: function()
2589 if (this.parent().type == 'treeview') {
2590 this.el.select('a').on('click', this.onClick, this);
2594 this.menu.parentType = this.xtype;
2595 this.menu.triggerEl = this.el;
2596 this.menu = this.addxtype(Roo.apply({}, this.menu));
2600 onClick : function(e)
2602 Roo.log('item on click ');
2604 if(this.preventDefault){
2607 //this.parent().hideMenuItems();
2609 this.fireEvent('click', this, e);
2628 * @class Roo.bootstrap.MenuSeparator
2629 * @extends Roo.bootstrap.Component
2630 * Bootstrap MenuSeparator class
2633 * Create a new MenuItem
2634 * @param {Object} config The config object
2638 Roo.bootstrap.MenuSeparator = function(config){
2639 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2642 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2644 getAutoCreate : function(){
2663 * @class Roo.bootstrap.Modal
2664 * @extends Roo.bootstrap.Component
2665 * Bootstrap Modal class
2666 * @cfg {String} title Title of dialog
2667 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2668 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2669 * @cfg {Boolean} specificTitle default false
2670 * @cfg {Array} buttons Array of buttons or standard button set..
2671 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2672 * @cfg {Boolean} animate default true
2673 * @cfg {Boolean} allow_close default true
2674 * @cfg {Boolean} fitwindow default false
2675 * @cfg {String} size (sm|lg) default empty
2676 * @cfg {Number} max_width set the max width of modal
2680 * Create a new Modal Dialog
2681 * @param {Object} config The config object
2684 Roo.bootstrap.Modal = function(config){
2685 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2690 * The raw btnclick event for the button
2691 * @param {Roo.EventObject} e
2696 * Fire when dialog resize
2697 * @param {Roo.bootstrap.Modal} this
2698 * @param {Roo.EventObject} e
2702 this.buttons = this.buttons || [];
2705 this.tmpl = Roo.factory(this.tmpl);
2710 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2712 title : 'test dialog',
2722 specificTitle: false,
2724 buttonPosition: 'right',
2747 onRender : function(ct, position)
2749 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2752 var cfg = Roo.apply({}, this.getAutoCreate());
2755 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2757 //if (!cfg.name.length) {
2761 cfg.cls += ' ' + this.cls;
2764 cfg.style = this.style;
2766 this.el = Roo.get(document.body).createChild(cfg, position);
2768 //var type = this.el.dom.type;
2771 if(this.tabIndex !== undefined){
2772 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2775 this.dialogEl = this.el.select('.modal-dialog',true).first();
2776 this.bodyEl = this.el.select('.modal-body',true).first();
2777 this.closeEl = this.el.select('.modal-header .close', true).first();
2778 this.headerEl = this.el.select('.modal-header',true).first();
2779 this.titleEl = this.el.select('.modal-title',true).first();
2780 this.footerEl = this.el.select('.modal-footer',true).first();
2782 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2784 //this.el.addClass("x-dlg-modal");
2786 if (this.buttons.length) {
2787 Roo.each(this.buttons, function(bb) {
2788 var b = Roo.apply({}, bb);
2789 b.xns = b.xns || Roo.bootstrap;
2790 b.xtype = b.xtype || 'Button';
2791 if (typeof(b.listeners) == 'undefined') {
2792 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2795 var btn = Roo.factory(b);
2797 btn.render(this.getButtonContainer());
2801 // render the children.
2804 if(typeof(this.items) != 'undefined'){
2805 var items = this.items;
2808 for(var i =0;i < items.length;i++) {
2809 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2813 this.items = nitems;
2815 // where are these used - they used to be body/close/footer
2819 //this.el.addClass([this.fieldClass, this.cls]);
2823 getAutoCreate : function()
2827 html : this.html || ''
2832 cls : 'modal-title',
2836 if(this.specificTitle){
2842 if (this.allow_close && Roo.bootstrap.version == 3) {
2852 if (this.allow_close && Roo.bootstrap.version == 4) {
2862 if(this.size.length){
2863 size = 'modal-' + this.size;
2866 var footer = Roo.bootstrap.version == 3 ?
2868 cls : 'modal-footer',
2872 cls: 'btn-' + this.buttonPosition
2877 { // BS4 uses mr-auto on left buttons....
2878 cls : 'modal-footer'
2889 cls: "modal-dialog " + size,
2892 cls : "modal-content",
2895 cls : 'modal-header',
2910 modal.cls += ' fade';
2916 getChildContainer : function() {
2921 getButtonContainer : function() {
2923 return Roo.bootstrap.version == 4 ?
2924 this.el.select('.modal-footer',true).first()
2925 : this.el.select('.modal-footer div',true).first();
2928 initEvents : function()
2930 if (this.allow_close) {
2931 this.closeEl.on('click', this.hide, this);
2933 Roo.EventManager.onWindowResize(this.resize, this, true);
2941 this.maskEl.setSize(
2942 Roo.lib.Dom.getViewWidth(true),
2943 Roo.lib.Dom.getViewHeight(true)
2946 if (this.fitwindow) {
2950 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2951 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2956 if(this.max_width !== 0) {
2958 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2961 this.setSize(w, this.height);
2965 if(this.max_height) {
2966 this.setSize(w,Math.min(
2968 Roo.lib.Dom.getViewportHeight(true) - 60
2974 if(!this.fit_content) {
2975 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2979 this.setSize(w, Math.min(
2981 this.headerEl.getHeight() +
2982 this.footerEl.getHeight() +
2983 this.getChildHeight(this.bodyEl.dom.childNodes),
2984 Roo.lib.Dom.getViewportHeight(true) - 60)
2990 setSize : function(w,h)
3001 if (!this.rendered) {
3005 //this.el.setStyle('display', 'block');
3006 this.el.removeClass('hideing');
3007 this.el.dom.style.display='block';
3009 Roo.get(document.body).addClass('modal-open');
3011 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
3014 this.el.addClass('show');
3015 this.el.addClass('in');
3018 this.el.addClass('show');
3019 this.el.addClass('in');
3022 // not sure how we can show data in here..
3024 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3027 Roo.get(document.body).addClass("x-body-masked");
3029 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3030 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3031 this.maskEl.dom.style.display = 'block';
3032 this.maskEl.addClass('show');
3037 this.fireEvent('show', this);
3039 // set zindex here - otherwise it appears to be ignored...
3040 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3043 this.items.forEach( function(e) {
3044 e.layout ? e.layout() : false;
3052 if(this.fireEvent("beforehide", this) !== false){
3054 this.maskEl.removeClass('show');
3056 this.maskEl.dom.style.display = '';
3057 Roo.get(document.body).removeClass("x-body-masked");
3058 this.el.removeClass('in');
3059 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3061 if(this.animate){ // why
3062 this.el.addClass('hideing');
3063 this.el.removeClass('show');
3065 if (!this.el.hasClass('hideing')) {
3066 return; // it's been shown again...
3069 this.el.dom.style.display='';
3071 Roo.get(document.body).removeClass('modal-open');
3072 this.el.removeClass('hideing');
3076 this.el.removeClass('show');
3077 this.el.dom.style.display='';
3078 Roo.get(document.body).removeClass('modal-open');
3081 this.fireEvent('hide', this);
3084 isVisible : function()
3087 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3091 addButton : function(str, cb)
3095 var b = Roo.apply({}, { html : str } );
3096 b.xns = b.xns || Roo.bootstrap;
3097 b.xtype = b.xtype || 'Button';
3098 if (typeof(b.listeners) == 'undefined') {
3099 b.listeners = { click : cb.createDelegate(this) };
3102 var btn = Roo.factory(b);
3104 btn.render(this.getButtonContainer());
3110 setDefaultButton : function(btn)
3112 //this.el.select('.modal-footer').()
3115 resizeTo: function(w,h)
3117 this.dialogEl.setWidth(w);
3119 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3121 this.bodyEl.setHeight(h - diff);
3123 this.fireEvent('resize', this);
3126 setContentSize : function(w, h)
3130 onButtonClick: function(btn,e)
3133 this.fireEvent('btnclick', btn.name, e);
3136 * Set the title of the Dialog
3137 * @param {String} str new Title
3139 setTitle: function(str) {
3140 this.titleEl.dom.innerHTML = str;
3143 * Set the body of the Dialog
3144 * @param {String} str new Title
3146 setBody: function(str) {
3147 this.bodyEl.dom.innerHTML = str;
3150 * Set the body of the Dialog using the template
3151 * @param {Obj} data - apply this data to the template and replace the body contents.
3153 applyBody: function(obj)
3156 Roo.log("Error - using apply Body without a template");
3159 this.tmpl.overwrite(this.bodyEl, obj);
3162 getChildHeight : function(child_nodes)
3166 child_nodes.length == 0
3171 var child_height = 0;
3173 for(var i = 0; i < child_nodes.length; i++) {
3176 * for modal with tabs...
3177 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3179 var layout_childs = child_nodes[i].childNodes;
3181 for(var j = 0; j < layout_childs.length; j++) {
3183 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3185 var layout_body_childs = layout_childs[j].childNodes;
3187 for(var k = 0; k < layout_body_childs.length; k++) {
3189 if(layout_body_childs[k].classList.contains('navbar')) {
3190 child_height += layout_body_childs[k].offsetHeight;
3194 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3196 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3198 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3200 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3201 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3216 child_height += child_nodes[i].offsetHeight;
3217 // Roo.log(child_nodes[i].offsetHeight);
3220 return child_height;
3226 Roo.apply(Roo.bootstrap.Modal, {
3228 * Button config that displays a single OK button
3237 * Button config that displays Yes and No buttons
3253 * Button config that displays OK and Cancel buttons
3268 * Button config that displays Yes, No and Cancel buttons
3292 * messagebox - can be used as a replace
3296 * @class Roo.MessageBox
3297 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3301 Roo.Msg.alert('Status', 'Changes saved successfully.');
3303 // Prompt for user data:
3304 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3306 // process text value...
3310 // Show a dialog using config options:
3312 title:'Save Changes?',
3313 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3314 buttons: Roo.Msg.YESNOCANCEL,
3321 Roo.bootstrap.MessageBox = function(){
3322 var dlg, opt, mask, waitTimer;
3323 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3324 var buttons, activeTextEl, bwidth;
3328 var handleButton = function(button){
3330 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3334 var handleHide = function(){
3336 dlg.el.removeClass(opt.cls);
3339 // Roo.TaskMgr.stop(waitTimer);
3340 // waitTimer = null;
3345 var updateButtons = function(b){
3348 buttons["ok"].hide();
3349 buttons["cancel"].hide();
3350 buttons["yes"].hide();
3351 buttons["no"].hide();
3352 dlg.footerEl.hide();
3356 dlg.footerEl.show();
3357 for(var k in buttons){
3358 if(typeof buttons[k] != "function"){
3361 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3362 width += buttons[k].el.getWidth()+15;
3372 var handleEsc = function(d, k, e){
3373 if(opt && opt.closable !== false){
3383 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3384 * @return {Roo.BasicDialog} The BasicDialog element
3386 getDialog : function(){
3388 dlg = new Roo.bootstrap.Modal( {
3391 //constraintoviewport:false,
3393 //collapsible : false,
3398 //buttonAlign:"center",
3399 closeClick : function(){
3400 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3403 handleButton("cancel");
3408 dlg.on("hide", handleHide);
3410 //dlg.addKeyListener(27, handleEsc);
3412 this.buttons = buttons;
3413 var bt = this.buttonText;
3414 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3415 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3416 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3417 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3419 bodyEl = dlg.bodyEl.createChild({
3421 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3422 '<textarea class="roo-mb-textarea"></textarea>' +
3423 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3425 msgEl = bodyEl.dom.firstChild;
3426 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3427 textboxEl.enableDisplayMode();
3428 textboxEl.addKeyListener([10,13], function(){
3429 if(dlg.isVisible() && opt && opt.buttons){
3432 }else if(opt.buttons.yes){
3433 handleButton("yes");
3437 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3438 textareaEl.enableDisplayMode();
3439 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3440 progressEl.enableDisplayMode();
3442 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3443 var pf = progressEl.dom.firstChild;
3445 pp = Roo.get(pf.firstChild);
3446 pp.setHeight(pf.offsetHeight);
3454 * Updates the message box body text
3455 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3456 * the XHTML-compliant non-breaking space character '&#160;')
3457 * @return {Roo.MessageBox} This message box
3459 updateText : function(text)
3461 if(!dlg.isVisible() && !opt.width){
3462 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3463 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3465 msgEl.innerHTML = text || ' ';
3467 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3468 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3470 Math.min(opt.width || cw , this.maxWidth),
3471 Math.max(opt.minWidth || this.minWidth, bwidth)
3474 activeTextEl.setWidth(w);
3476 if(dlg.isVisible()){
3477 dlg.fixedcenter = false;
3479 // to big, make it scroll. = But as usual stupid IE does not support
3482 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3483 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3484 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3486 bodyEl.dom.style.height = '';
3487 bodyEl.dom.style.overflowY = '';
3490 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3492 bodyEl.dom.style.overflowX = '';
3495 dlg.setContentSize(w, bodyEl.getHeight());
3496 if(dlg.isVisible()){
3497 dlg.fixedcenter = true;
3503 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3504 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3505 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3506 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3507 * @return {Roo.MessageBox} This message box
3509 updateProgress : function(value, text){
3511 this.updateText(text);
3514 if (pp) { // weird bug on my firefox - for some reason this is not defined
3515 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3516 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3522 * Returns true if the message box is currently displayed
3523 * @return {Boolean} True if the message box is visible, else false
3525 isVisible : function(){
3526 return dlg && dlg.isVisible();
3530 * Hides the message box if it is displayed
3533 if(this.isVisible()){
3539 * Displays a new message box, or reinitializes an existing message box, based on the config options
3540 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3541 * The following config object properties are supported:
3543 Property Type Description
3544 ---------- --------------- ------------------------------------------------------------------------------------
3545 animEl String/Element An id or Element from which the message box should animate as it opens and
3546 closes (defaults to undefined)
3547 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3548 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3549 closable Boolean False to hide the top-right close button (defaults to true). Note that
3550 progress and wait dialogs will ignore this property and always hide the
3551 close button as they can only be closed programmatically.
3552 cls String A custom CSS class to apply to the message box element
3553 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3554 displayed (defaults to 75)
3555 fn Function A callback function to execute after closing the dialog. The arguments to the
3556 function will be btn (the name of the button that was clicked, if applicable,
3557 e.g. "ok"), and text (the value of the active text field, if applicable).
3558 Progress and wait dialogs will ignore this option since they do not respond to
3559 user actions and can only be closed programmatically, so any required function
3560 should be called by the same code after it closes the dialog.
3561 icon String A CSS class that provides a background image to be used as an icon for
3562 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3563 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3564 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3565 modal Boolean False to allow user interaction with the page while the message box is
3566 displayed (defaults to true)
3567 msg String A string that will replace the existing message box body text (defaults
3568 to the XHTML-compliant non-breaking space character ' ')
3569 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3570 progress Boolean True to display a progress bar (defaults to false)
3571 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3572 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3573 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3574 title String The title text
3575 value String The string value to set into the active textbox element if displayed
3576 wait Boolean True to display a progress bar (defaults to false)
3577 width Number The width of the dialog in pixels
3584 msg: 'Please enter your address:',
3586 buttons: Roo.MessageBox.OKCANCEL,
3589 animEl: 'addAddressBtn'
3592 * @param {Object} config Configuration options
3593 * @return {Roo.MessageBox} This message box
3595 show : function(options)
3598 // this causes nightmares if you show one dialog after another
3599 // especially on callbacks..
3601 if(this.isVisible()){
3604 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3605 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3606 Roo.log("New Dialog Message:" + options.msg )
3607 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3608 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3611 var d = this.getDialog();
3613 d.setTitle(opt.title || " ");
3614 d.closeEl.setDisplayed(opt.closable !== false);
3615 activeTextEl = textboxEl;
3616 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3621 textareaEl.setHeight(typeof opt.multiline == "number" ?
3622 opt.multiline : this.defaultTextHeight);
3623 activeTextEl = textareaEl;
3632 progressEl.setDisplayed(opt.progress === true);
3634 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3636 this.updateProgress(0);
3637 activeTextEl.dom.value = opt.value || "";
3639 dlg.setDefaultButton(activeTextEl);
3641 var bs = opt.buttons;
3645 }else if(bs && bs.yes){
3646 db = buttons["yes"];
3648 dlg.setDefaultButton(db);
3650 bwidth = updateButtons(opt.buttons);
3651 this.updateText(opt.msg);
3653 d.el.addClass(opt.cls);
3655 d.proxyDrag = opt.proxyDrag === true;
3656 d.modal = opt.modal !== false;
3657 d.mask = opt.modal !== false ? mask : false;
3659 // force it to the end of the z-index stack so it gets a cursor in FF
3660 document.body.appendChild(dlg.el.dom);
3661 d.animateTarget = null;
3662 d.show(options.animEl);
3668 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3669 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3670 * and closing the message box when the process is complete.
3671 * @param {String} title The title bar text
3672 * @param {String} msg The message box body text
3673 * @return {Roo.MessageBox} This message box
3675 progress : function(title, msg){
3682 minWidth: this.minProgressWidth,
3689 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3690 * If a callback function is passed it will be called after the user clicks the button, and the
3691 * id of the button that was clicked will be passed as the only parameter to the callback
3692 * (could also be the top-right close button).
3693 * @param {String} title The title bar text
3694 * @param {String} msg The message box body text
3695 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3696 * @param {Object} scope (optional) The scope of the callback function
3697 * @return {Roo.MessageBox} This message box
3699 alert : function(title, msg, fn, scope)
3714 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3715 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3716 * You are responsible for closing the message box when the process is complete.
3717 * @param {String} msg The message box body text
3718 * @param {String} title (optional) The title bar text
3719 * @return {Roo.MessageBox} This message box
3721 wait : function(msg, title){
3732 waitTimer = Roo.TaskMgr.start({
3734 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3742 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3743 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3744 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3745 * @param {String} title The title bar text
3746 * @param {String} msg The message box body text
3747 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3748 * @param {Object} scope (optional) The scope of the callback function
3749 * @return {Roo.MessageBox} This message box
3751 confirm : function(title, msg, fn, scope){
3755 buttons: this.YESNO,
3764 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3765 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3766 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3767 * (could also be the top-right close button) and the text that was entered will be passed as the two
3768 * parameters to the callback.
3769 * @param {String} title The title bar text
3770 * @param {String} msg The message box body text
3771 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3772 * @param {Object} scope (optional) The scope of the callback function
3773 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3774 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3775 * @return {Roo.MessageBox} This message box
3777 prompt : function(title, msg, fn, scope, multiline){
3781 buttons: this.OKCANCEL,
3786 multiline: multiline,
3793 * Button config that displays a single OK button
3798 * Button config that displays Yes and No buttons
3801 YESNO : {yes:true, no:true},
3803 * Button config that displays OK and Cancel buttons
3806 OKCANCEL : {ok:true, cancel:true},
3808 * Button config that displays Yes, No and Cancel buttons
3811 YESNOCANCEL : {yes:true, no:true, cancel:true},
3814 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3817 defaultTextHeight : 75,
3819 * The maximum width in pixels of the message box (defaults to 600)
3824 * The minimum width in pixels of the message box (defaults to 100)
3829 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3830 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3833 minProgressWidth : 250,
3835 * An object containing the default button text strings that can be overriden for localized language support.
3836 * Supported properties are: ok, cancel, yes and no.
3837 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3850 * Shorthand for {@link Roo.MessageBox}
3852 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3853 Roo.Msg = Roo.Msg || Roo.MessageBox;
3862 * @class Roo.bootstrap.Navbar
3863 * @extends Roo.bootstrap.Component
3864 * Bootstrap Navbar class
3867 * Create a new Navbar
3868 * @param {Object} config The config object
3872 Roo.bootstrap.Navbar = function(config){
3873 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3877 * @event beforetoggle
3878 * Fire before toggle the menu
3879 * @param {Roo.EventObject} e
3881 "beforetoggle" : true
3885 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3894 getAutoCreate : function(){
3897 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3901 initEvents :function ()
3903 //Roo.log(this.el.select('.navbar-toggle',true));
3904 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3911 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3913 var size = this.el.getSize();
3914 this.maskEl.setSize(size.width, size.height);
3915 this.maskEl.enableDisplayMode("block");
3924 getChildContainer : function()
3926 if (this.el && this.el.select('.collapse').getCount()) {
3927 return this.el.select('.collapse',true).first();
3942 onToggle : function()
3945 if(this.fireEvent('beforetoggle', this) === false){
3948 var ce = this.el.select('.navbar-collapse',true).first();
3950 if (!ce.hasClass('show')) {
3960 * Expand the navbar pulldown
3962 expand : function ()
3965 var ce = this.el.select('.navbar-collapse',true).first();
3966 if (ce.hasClass('collapsing')) {
3969 ce.dom.style.height = '';
3971 ce.addClass('in'); // old...
3972 ce.removeClass('collapse');
3973 ce.addClass('show');
3974 var h = ce.getHeight();
3976 ce.removeClass('show');
3977 // at this point we should be able to see it..
3978 ce.addClass('collapsing');
3980 ce.setHeight(0); // resize it ...
3981 ce.on('transitionend', function() {
3982 //Roo.log('done transition');
3983 ce.removeClass('collapsing');
3984 ce.addClass('show');
3985 ce.removeClass('collapse');
3987 ce.dom.style.height = '';
3988 }, this, { single: true} );
3990 ce.dom.scrollTop = 0;
3993 * Collapse the navbar pulldown
3995 collapse : function()
3997 var ce = this.el.select('.navbar-collapse',true).first();
3999 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
4000 // it's collapsed or collapsing..
4003 ce.removeClass('in'); // old...
4004 ce.setHeight(ce.getHeight());
4005 ce.removeClass('show');
4006 ce.addClass('collapsing');
4008 ce.on('transitionend', function() {
4009 ce.dom.style.height = '';
4010 ce.removeClass('collapsing');
4011 ce.addClass('collapse');
4012 }, this, { single: true} );
4032 * @class Roo.bootstrap.NavSimplebar
4033 * @extends Roo.bootstrap.Navbar
4034 * Bootstrap Sidebar class
4036 * @cfg {Boolean} inverse is inverted color
4038 * @cfg {String} type (nav | pills | tabs)
4039 * @cfg {Boolean} arrangement stacked | justified
4040 * @cfg {String} align (left | right) alignment
4042 * @cfg {Boolean} main (true|false) main nav bar? default false
4043 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4045 * @cfg {String} tag (header|footer|nav|div) default is nav
4047 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4051 * Create a new Sidebar
4052 * @param {Object} config The config object
4056 Roo.bootstrap.NavSimplebar = function(config){
4057 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4060 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4076 getAutoCreate : function(){
4080 tag : this.tag || 'div',
4081 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
4083 if (['light','white'].indexOf(this.weight) > -1) {
4084 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4086 cfg.cls += ' bg-' + this.weight;
4089 cfg.cls += ' navbar-inverse';
4093 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4095 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
4104 cls: 'nav nav-' + this.xtype,
4110 this.type = this.type || 'nav';
4111 if (['tabs','pills'].indexOf(this.type) != -1) {
4112 cfg.cn[0].cls += ' nav-' + this.type
4116 if (this.type!=='nav') {
4117 Roo.log('nav type must be nav/tabs/pills')
4119 cfg.cn[0].cls += ' navbar-nav'
4125 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4126 cfg.cn[0].cls += ' nav-' + this.arrangement;
4130 if (this.align === 'right') {
4131 cfg.cn[0].cls += ' navbar-right';
4156 * navbar-expand-md fixed-top
4160 * @class Roo.bootstrap.NavHeaderbar
4161 * @extends Roo.bootstrap.NavSimplebar
4162 * Bootstrap Sidebar class
4164 * @cfg {String} brand what is brand
4165 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4166 * @cfg {String} brand_href href of the brand
4167 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4168 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4169 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4170 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4173 * Create a new Sidebar
4174 * @param {Object} config The config object
4178 Roo.bootstrap.NavHeaderbar = function(config){
4179 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4183 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4190 desktopCenter : false,
4193 getAutoCreate : function(){
4196 tag: this.nav || 'nav',
4197 cls: 'navbar navbar-expand-md',
4203 if (this.desktopCenter) {
4204 cn.push({cls : 'container', cn : []});
4212 cls: 'navbar-toggle navbar-toggler',
4213 'data-toggle': 'collapse',
4218 html: 'Toggle navigation'
4222 cls: 'icon-bar navbar-toggler-icon'
4235 cn.push( Roo.bootstrap.version == 4 ? btn : {
4237 cls: 'navbar-header',
4246 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
4250 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4252 if (['light','white'].indexOf(this.weight) > -1) {
4253 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4255 cfg.cls += ' bg-' + this.weight;
4258 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4259 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4261 // tag can override this..
4263 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4266 if (this.brand !== '') {
4267 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4268 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4270 href: this.brand_href ? this.brand_href : '#',
4271 cls: 'navbar-brand',
4279 cfg.cls += ' main-nav';
4287 getHeaderChildContainer : function()
4289 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4290 return this.el.select('.navbar-header',true).first();
4293 return this.getChildContainer();
4297 initEvents : function()
4299 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4301 if (this.autohide) {
4306 Roo.get(document).on('scroll',function(e) {
4307 var ns = Roo.get(document).getScroll().top;
4308 var os = prevScroll;
4312 ft.removeClass('slideDown');
4313 ft.addClass('slideUp');
4316 ft.removeClass('slideUp');
4317 ft.addClass('slideDown');
4338 * @class Roo.bootstrap.NavSidebar
4339 * @extends Roo.bootstrap.Navbar
4340 * Bootstrap Sidebar class
4343 * Create a new Sidebar
4344 * @param {Object} config The config object
4348 Roo.bootstrap.NavSidebar = function(config){
4349 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4352 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4354 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4356 getAutoCreate : function(){
4361 cls: 'sidebar sidebar-nav'
4383 * @class Roo.bootstrap.NavGroup
4384 * @extends Roo.bootstrap.Component
4385 * Bootstrap NavGroup class
4386 * @cfg {String} align (left|right)
4387 * @cfg {Boolean} inverse
4388 * @cfg {String} type (nav|pills|tab) default nav
4389 * @cfg {String} navId - reference Id for navbar.
4393 * Create a new nav group
4394 * @param {Object} config The config object
4397 Roo.bootstrap.NavGroup = function(config){
4398 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4401 Roo.bootstrap.NavGroup.register(this);
4405 * Fires when the active item changes
4406 * @param {Roo.bootstrap.NavGroup} this
4407 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4408 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4415 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4426 getAutoCreate : function()
4428 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4434 if (Roo.bootstrap.version == 4) {
4435 if (['tabs','pills'].indexOf(this.type) != -1) {
4436 cfg.cls += ' nav-' + this.type;
4438 // trying to remove so header bar can right align top?
4439 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
4440 // do not use on header bar...
4441 cfg.cls += ' navbar-nav';
4446 if (['tabs','pills'].indexOf(this.type) != -1) {
4447 cfg.cls += ' nav-' + this.type
4449 if (this.type !== 'nav') {
4450 Roo.log('nav type must be nav/tabs/pills')
4452 cfg.cls += ' navbar-nav'
4456 if (this.parent() && this.parent().sidebar) {
4459 cls: 'dashboard-menu sidebar-menu'
4465 if (this.form === true) {
4468 cls: 'navbar-form form-inline'
4470 //nav navbar-right ml-md-auto
4471 if (this.align === 'right') {
4472 cfg.cls += ' navbar-right ml-md-auto';
4474 cfg.cls += ' navbar-left';
4478 if (this.align === 'right') {
4479 cfg.cls += ' navbar-right ml-md-auto';
4481 cfg.cls += ' mr-auto';
4485 cfg.cls += ' navbar-inverse';
4493 * sets the active Navigation item
4494 * @param {Roo.bootstrap.NavItem} the new current navitem
4496 setActiveItem : function(item)
4499 Roo.each(this.navItems, function(v){
4504 v.setActive(false, true);
4511 item.setActive(true, true);
4512 this.fireEvent('changed', this, item, prev);
4517 * gets the active Navigation item
4518 * @return {Roo.bootstrap.NavItem} the current navitem
4520 getActive : function()
4524 Roo.each(this.navItems, function(v){
4535 indexOfNav : function()
4539 Roo.each(this.navItems, function(v,i){
4550 * adds a Navigation item
4551 * @param {Roo.bootstrap.NavItem} the navitem to add
4553 addItem : function(cfg)
4555 if (this.form && Roo.bootstrap.version == 4) {
4558 var cn = new Roo.bootstrap.NavItem(cfg);
4560 cn.parentId = this.id;
4561 cn.onRender(this.el, null);
4565 * register a Navigation item
4566 * @param {Roo.bootstrap.NavItem} the navitem to add
4568 register : function(item)
4570 this.navItems.push( item);
4571 item.navId = this.navId;
4576 * clear all the Navigation item
4579 clearAll : function()
4582 this.el.dom.innerHTML = '';
4585 getNavItem: function(tabId)
4588 Roo.each(this.navItems, function(e) {
4589 if (e.tabId == tabId) {
4599 setActiveNext : function()
4601 var i = this.indexOfNav(this.getActive());
4602 if (i > this.navItems.length) {
4605 this.setActiveItem(this.navItems[i+1]);
4607 setActivePrev : function()
4609 var i = this.indexOfNav(this.getActive());
4613 this.setActiveItem(this.navItems[i-1]);
4615 clearWasActive : function(except) {
4616 Roo.each(this.navItems, function(e) {
4617 if (e.tabId != except.tabId && e.was_active) {
4618 e.was_active = false;
4625 getWasActive : function ()
4628 Roo.each(this.navItems, function(e) {
4643 Roo.apply(Roo.bootstrap.NavGroup, {
4647 * register a Navigation Group
4648 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4650 register : function(navgrp)
4652 this.groups[navgrp.navId] = navgrp;
4656 * fetch a Navigation Group based on the navigation ID
4657 * @param {string} the navgroup to add
4658 * @returns {Roo.bootstrap.NavGroup} the navgroup
4660 get: function(navId) {
4661 if (typeof(this.groups[navId]) == 'undefined') {
4663 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4665 return this.groups[navId] ;
4680 * @class Roo.bootstrap.NavItem
4681 * @extends Roo.bootstrap.Component
4682 * Bootstrap Navbar.NavItem class
4683 * @cfg {String} href link to
4684 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4686 * @cfg {String} html content of button
4687 * @cfg {String} badge text inside badge
4688 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4689 * @cfg {String} glyphicon DEPRICATED - use fa
4690 * @cfg {String} icon DEPRICATED - use fa
4691 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4692 * @cfg {Boolean} active Is item active
4693 * @cfg {Boolean} disabled Is item disabled
4695 * @cfg {Boolean} preventDefault (true | false) default false
4696 * @cfg {String} tabId the tab that this item activates.
4697 * @cfg {String} tagtype (a|span) render as a href or span?
4698 * @cfg {Boolean} animateRef (true|false) link to element default false
4701 * Create a new Navbar Item
4702 * @param {Object} config The config object
4704 Roo.bootstrap.NavItem = function(config){
4705 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4710 * The raw click event for the entire grid.
4711 * @param {Roo.EventObject} e
4716 * Fires when the active item active state changes
4717 * @param {Roo.bootstrap.NavItem} this
4718 * @param {boolean} state the new state
4724 * Fires when scroll to element
4725 * @param {Roo.bootstrap.NavItem} this
4726 * @param {Object} options
4727 * @param {Roo.EventObject} e
4735 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4744 preventDefault : false,
4752 button_outline : false,
4756 getAutoCreate : function(){
4764 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4766 if (this.disabled) {
4767 cfg.cls += ' disabled';
4771 if (this.button_weight.length) {
4772 cfg.tag = this.href ? 'a' : 'button';
4773 cfg.html = this.html || '';
4774 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4776 cfg.href = this.href;
4779 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4782 // menu .. should add dropdown-menu class - so no need for carat..
4784 if (this.badge !== '') {
4786 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4791 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4795 href : this.href || "#",
4796 html: this.html || ''
4799 if (this.tagtype == 'a') {
4800 cfg.cn[0].cls = 'nav-link';
4803 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4806 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4808 if(this.glyphicon) {
4809 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4814 cfg.cn[0].html += " <span class='caret'></span>";
4818 if (this.badge !== '') {
4820 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4828 onRender : function(ct, position)
4830 // Roo.log("Call onRender: " + this.xtype);
4831 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4835 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4836 this.navLink = this.el.select('.nav-link',true).first();
4841 initEvents: function()
4843 if (typeof (this.menu) != 'undefined') {
4844 this.menu.parentType = this.xtype;
4845 this.menu.triggerEl = this.el;
4846 this.menu = this.addxtype(Roo.apply({}, this.menu));
4849 this.el.select('a',true).on('click', this.onClick, this);
4851 if(this.tagtype == 'span'){
4852 this.el.select('span',true).on('click', this.onClick, this);
4855 // at this point parent should be available..
4856 this.parent().register(this);
4859 onClick : function(e)
4861 if (e.getTarget('.dropdown-menu-item')) {
4862 // did you click on a menu itemm.... - then don't trigger onclick..
4867 this.preventDefault ||
4870 Roo.log("NavItem - prevent Default?");
4874 if (this.disabled) {
4878 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4879 if (tg && tg.transition) {
4880 Roo.log("waiting for the transitionend");
4886 //Roo.log("fire event clicked");
4887 if(this.fireEvent('click', this, e) === false){
4891 if(this.tagtype == 'span'){
4895 //Roo.log(this.href);
4896 var ael = this.el.select('a',true).first();
4899 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4900 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4901 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4902 return; // ignore... - it's a 'hash' to another page.
4904 Roo.log("NavItem - prevent Default?");
4906 this.scrollToElement(e);
4910 var p = this.parent();
4912 if (['tabs','pills'].indexOf(p.type)!==-1) {
4913 if (typeof(p.setActiveItem) !== 'undefined') {
4914 p.setActiveItem(this);
4918 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4919 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4920 // remove the collapsed menu expand...
4921 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
4925 isActive: function () {
4928 setActive : function(state, fire, is_was_active)
4930 if (this.active && !state && this.navId) {
4931 this.was_active = true;
4932 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4934 nv.clearWasActive(this);
4938 this.active = state;
4941 this.el.removeClass('active');
4942 this.navLink ? this.navLink.removeClass('active') : false;
4943 } else if (!this.el.hasClass('active')) {
4945 this.el.addClass('active');
4946 if (Roo.bootstrap.version == 4 && this.navLink ) {
4947 this.navLink.addClass('active');
4952 this.fireEvent('changed', this, state);
4955 // show a panel if it's registered and related..
4957 if (!this.navId || !this.tabId || !state || is_was_active) {
4961 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4965 var pan = tg.getPanelByName(this.tabId);
4969 // if we can not flip to new panel - go back to old nav highlight..
4970 if (false == tg.showPanel(pan)) {
4971 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4973 var onav = nv.getWasActive();
4975 onav.setActive(true, false, true);
4984 // this should not be here...
4985 setDisabled : function(state)
4987 this.disabled = state;
4989 this.el.removeClass('disabled');
4990 } else if (!this.el.hasClass('disabled')) {
4991 this.el.addClass('disabled');
4997 * Fetch the element to display the tooltip on.
4998 * @return {Roo.Element} defaults to this.el
5000 tooltipEl : function()
5002 return this.el.select('' + this.tagtype + '', true).first();
5005 scrollToElement : function(e)
5007 var c = document.body;
5010 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
5012 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
5013 c = document.documentElement;
5016 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
5022 var o = target.calcOffsetsTo(c);
5029 this.fireEvent('scrollto', this, options, e);
5031 Roo.get(c).scrollTo('top', options.value, true);
5044 * <span> icon </span>
5045 * <span> text </span>
5046 * <span>badge </span>
5050 * @class Roo.bootstrap.NavSidebarItem
5051 * @extends Roo.bootstrap.NavItem
5052 * Bootstrap Navbar.NavSidebarItem class
5053 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5054 * {Boolean} open is the menu open
5055 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5056 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5057 * {String} buttonSize (sm|md|lg)the extra classes for the button
5058 * {Boolean} showArrow show arrow next to the text (default true)
5060 * Create a new Navbar Button
5061 * @param {Object} config The config object
5063 Roo.bootstrap.NavSidebarItem = function(config){
5064 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5069 * The raw click event for the entire grid.
5070 * @param {Roo.EventObject} e
5075 * Fires when the active item active state changes
5076 * @param {Roo.bootstrap.NavSidebarItem} this
5077 * @param {boolean} state the new state
5085 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5087 badgeWeight : 'default',
5093 buttonWeight : 'default',
5099 getAutoCreate : function(){
5104 href : this.href || '#',
5110 if(this.buttonView){
5113 href : this.href || '#',
5114 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5127 cfg.cls += ' active';
5130 if (this.disabled) {
5131 cfg.cls += ' disabled';
5134 cfg.cls += ' open x-open';
5137 if (this.glyphicon || this.icon) {
5138 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5139 a.cn.push({ tag : 'i', cls : c }) ;
5142 if(!this.buttonView){
5145 html : this.html || ''
5152 if (this.badge !== '') {
5153 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5159 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5162 a.cls += ' dropdown-toggle treeview' ;
5168 initEvents : function()
5170 if (typeof (this.menu) != 'undefined') {
5171 this.menu.parentType = this.xtype;
5172 this.menu.triggerEl = this.el;
5173 this.menu = this.addxtype(Roo.apply({}, this.menu));
5176 this.el.on('click', this.onClick, this);
5178 if(this.badge !== ''){
5179 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5184 onClick : function(e)
5191 if(this.preventDefault){
5195 this.fireEvent('click', this, e);
5198 disable : function()
5200 this.setDisabled(true);
5205 this.setDisabled(false);
5208 setDisabled : function(state)
5210 if(this.disabled == state){
5214 this.disabled = state;
5217 this.el.addClass('disabled');
5221 this.el.removeClass('disabled');
5226 setActive : function(state)
5228 if(this.active == state){
5232 this.active = state;
5235 this.el.addClass('active');
5239 this.el.removeClass('active');
5244 isActive: function ()
5249 setBadge : function(str)
5255 this.badgeEl.dom.innerHTML = str;
5272 * @class Roo.bootstrap.Row
5273 * @extends Roo.bootstrap.Component
5274 * Bootstrap Row class (contains columns...)
5278 * @param {Object} config The config object
5281 Roo.bootstrap.Row = function(config){
5282 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5285 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5287 getAutoCreate : function(){
5306 * @class Roo.bootstrap.Element
5307 * @extends Roo.bootstrap.Component
5308 * Bootstrap Element class
5309 * @cfg {String} html contents of the element
5310 * @cfg {String} tag tag of the element
5311 * @cfg {String} cls class of the element
5312 * @cfg {Boolean} preventDefault (true|false) default false
5313 * @cfg {Boolean} clickable (true|false) default false
5316 * Create a new Element
5317 * @param {Object} config The config object
5320 Roo.bootstrap.Element = function(config){
5321 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5327 * When a element is chick
5328 * @param {Roo.bootstrap.Element} this
5329 * @param {Roo.EventObject} e
5335 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5340 preventDefault: false,
5343 getAutoCreate : function(){
5347 // cls: this.cls, double assign in parent class Component.js :: onRender
5354 initEvents: function()
5356 Roo.bootstrap.Element.superclass.initEvents.call(this);
5359 this.el.on('click', this.onClick, this);
5364 onClick : function(e)
5366 if(this.preventDefault){
5370 this.fireEvent('click', this, e);
5373 getValue : function()
5375 return this.el.dom.innerHTML;
5378 setValue : function(value)
5380 this.el.dom.innerHTML = value;
5395 * @class Roo.bootstrap.Pagination
5396 * @extends Roo.bootstrap.Component
5397 * Bootstrap Pagination class
5398 * @cfg {String} size xs | sm | md | lg
5399 * @cfg {Boolean} inverse false | true
5402 * Create a new Pagination
5403 * @param {Object} config The config object
5406 Roo.bootstrap.Pagination = function(config){
5407 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5410 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5416 getAutoCreate : function(){
5422 cfg.cls += ' inverse';
5428 cfg.cls += " " + this.cls;
5446 * @class Roo.bootstrap.PaginationItem
5447 * @extends Roo.bootstrap.Component
5448 * Bootstrap PaginationItem class
5449 * @cfg {String} html text
5450 * @cfg {String} href the link
5451 * @cfg {Boolean} preventDefault (true | false) default true
5452 * @cfg {Boolean} active (true | false) default false
5453 * @cfg {Boolean} disabled default false
5457 * Create a new PaginationItem
5458 * @param {Object} config The config object
5462 Roo.bootstrap.PaginationItem = function(config){
5463 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5468 * The raw click event for the entire grid.
5469 * @param {Roo.EventObject} e
5475 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5479 preventDefault: true,
5484 getAutoCreate : function(){
5490 href : this.href ? this.href : '#',
5491 html : this.html ? this.html : ''
5501 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5505 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5511 initEvents: function() {
5513 this.el.on('click', this.onClick, this);
5516 onClick : function(e)
5518 Roo.log('PaginationItem on click ');
5519 if(this.preventDefault){
5527 this.fireEvent('click', this, e);
5543 * @class Roo.bootstrap.Slider
5544 * @extends Roo.bootstrap.Component
5545 * Bootstrap Slider class
5548 * Create a new Slider
5549 * @param {Object} config The config object
5552 Roo.bootstrap.Slider = function(config){
5553 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5556 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5558 getAutoCreate : function(){
5562 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5566 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5578 * Ext JS Library 1.1.1
5579 * Copyright(c) 2006-2007, Ext JS, LLC.
5581 * Originally Released Under LGPL - original licence link has changed is not relivant.
5584 * <script type="text/javascript">
5589 * @class Roo.grid.ColumnModel
5590 * @extends Roo.util.Observable
5591 * This is the default implementation of a ColumnModel used by the Grid. It defines
5592 * the columns in the grid.
5595 var colModel = new Roo.grid.ColumnModel([
5596 {header: "Ticker", width: 60, sortable: true, locked: true},
5597 {header: "Company Name", width: 150, sortable: true},
5598 {header: "Market Cap.", width: 100, sortable: true},
5599 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5600 {header: "Employees", width: 100, sortable: true, resizable: false}
5605 * The config options listed for this class are options which may appear in each
5606 * individual column definition.
5607 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5609 * @param {Object} config An Array of column config objects. See this class's
5610 * config objects for details.
5612 Roo.grid.ColumnModel = function(config){
5614 * The config passed into the constructor
5616 this.config = config;
5619 // if no id, create one
5620 // if the column does not have a dataIndex mapping,
5621 // map it to the order it is in the config
5622 for(var i = 0, len = config.length; i < len; i++){
5624 if(typeof c.dataIndex == "undefined"){
5627 if(typeof c.renderer == "string"){
5628 c.renderer = Roo.util.Format[c.renderer];
5630 if(typeof c.id == "undefined"){
5633 if(c.editor && c.editor.xtype){
5634 c.editor = Roo.factory(c.editor, Roo.grid);
5636 if(c.editor && c.editor.isFormField){
5637 c.editor = new Roo.grid.GridEditor(c.editor);
5639 this.lookup[c.id] = c;
5643 * The width of columns which have no width specified (defaults to 100)
5646 this.defaultWidth = 100;
5649 * Default sortable of columns which have no sortable specified (defaults to false)
5652 this.defaultSortable = false;
5656 * @event widthchange
5657 * Fires when the width of a column changes.
5658 * @param {ColumnModel} this
5659 * @param {Number} columnIndex The column index
5660 * @param {Number} newWidth The new width
5662 "widthchange": true,
5664 * @event headerchange
5665 * Fires when the text of a header changes.
5666 * @param {ColumnModel} this
5667 * @param {Number} columnIndex The column index
5668 * @param {Number} newText The new header text
5670 "headerchange": true,
5672 * @event hiddenchange
5673 * Fires when a column is hidden or "unhidden".
5674 * @param {ColumnModel} this
5675 * @param {Number} columnIndex The column index
5676 * @param {Boolean} hidden true if hidden, false otherwise
5678 "hiddenchange": true,
5680 * @event columnmoved
5681 * Fires when a column is moved.
5682 * @param {ColumnModel} this
5683 * @param {Number} oldIndex
5684 * @param {Number} newIndex
5686 "columnmoved" : true,
5688 * @event columlockchange
5689 * Fires when a column's locked state is changed
5690 * @param {ColumnModel} this
5691 * @param {Number} colIndex
5692 * @param {Boolean} locked true if locked
5694 "columnlockchange" : true
5696 Roo.grid.ColumnModel.superclass.constructor.call(this);
5698 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5700 * @cfg {String} header The header text to display in the Grid view.
5703 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5704 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5705 * specified, the column's index is used as an index into the Record's data Array.
5708 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5709 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5712 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5713 * Defaults to the value of the {@link #defaultSortable} property.
5714 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5717 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5720 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5723 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5726 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5729 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5730 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5731 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5732 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5735 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5738 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5741 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5744 * @cfg {String} cursor (Optional)
5747 * @cfg {String} tooltip (Optional)
5750 * @cfg {Number} xs (Optional)
5753 * @cfg {Number} sm (Optional)
5756 * @cfg {Number} md (Optional)
5759 * @cfg {Number} lg (Optional)
5762 * Returns the id of the column at the specified index.
5763 * @param {Number} index The column index
5764 * @return {String} the id
5766 getColumnId : function(index){
5767 return this.config[index].id;
5771 * Returns the column for a specified id.
5772 * @param {String} id The column id
5773 * @return {Object} the column
5775 getColumnById : function(id){
5776 return this.lookup[id];
5781 * Returns the column for a specified dataIndex.
5782 * @param {String} dataIndex The column dataIndex
5783 * @return {Object|Boolean} the column or false if not found
5785 getColumnByDataIndex: function(dataIndex){
5786 var index = this.findColumnIndex(dataIndex);
5787 return index > -1 ? this.config[index] : false;
5791 * Returns the index for a specified column id.
5792 * @param {String} id The column id
5793 * @return {Number} the index, or -1 if not found
5795 getIndexById : function(id){
5796 for(var i = 0, len = this.config.length; i < len; i++){
5797 if(this.config[i].id == id){
5805 * Returns the index for a specified column dataIndex.
5806 * @param {String} dataIndex The column dataIndex
5807 * @return {Number} the index, or -1 if not found
5810 findColumnIndex : function(dataIndex){
5811 for(var i = 0, len = this.config.length; i < len; i++){
5812 if(this.config[i].dataIndex == dataIndex){
5820 moveColumn : function(oldIndex, newIndex){
5821 var c = this.config[oldIndex];
5822 this.config.splice(oldIndex, 1);
5823 this.config.splice(newIndex, 0, c);
5824 this.dataMap = null;
5825 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5828 isLocked : function(colIndex){
5829 return this.config[colIndex].locked === true;
5832 setLocked : function(colIndex, value, suppressEvent){
5833 if(this.isLocked(colIndex) == value){
5836 this.config[colIndex].locked = value;
5838 this.fireEvent("columnlockchange", this, colIndex, value);
5842 getTotalLockedWidth : function(){
5844 for(var i = 0; i < this.config.length; i++){
5845 if(this.isLocked(i) && !this.isHidden(i)){
5846 this.totalWidth += this.getColumnWidth(i);
5852 getLockedCount : function(){
5853 for(var i = 0, len = this.config.length; i < len; i++){
5854 if(!this.isLocked(i)){
5859 return this.config.length;
5863 * Returns the number of columns.
5866 getColumnCount : function(visibleOnly){
5867 if(visibleOnly === true){
5869 for(var i = 0, len = this.config.length; i < len; i++){
5870 if(!this.isHidden(i)){
5876 return this.config.length;
5880 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5881 * @param {Function} fn
5882 * @param {Object} scope (optional)
5883 * @return {Array} result
5885 getColumnsBy : function(fn, scope){
5887 for(var i = 0, len = this.config.length; i < len; i++){
5888 var c = this.config[i];
5889 if(fn.call(scope||this, c, i) === true){
5897 * Returns true if the specified column is sortable.
5898 * @param {Number} col The column index
5901 isSortable : function(col){
5902 if(typeof this.config[col].sortable == "undefined"){
5903 return this.defaultSortable;
5905 return this.config[col].sortable;
5909 * Returns the rendering (formatting) function defined for the column.
5910 * @param {Number} col The column index.
5911 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5913 getRenderer : function(col){
5914 if(!this.config[col].renderer){
5915 return Roo.grid.ColumnModel.defaultRenderer;
5917 return this.config[col].renderer;
5921 * Sets the rendering (formatting) function for a column.
5922 * @param {Number} col The column index
5923 * @param {Function} fn The function to use to process the cell's raw data
5924 * to return HTML markup for the grid view. The render function is called with
5925 * the following parameters:<ul>
5926 * <li>Data value.</li>
5927 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5928 * <li>css A CSS style string to apply to the table cell.</li>
5929 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5930 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5931 * <li>Row index</li>
5932 * <li>Column index</li>
5933 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5935 setRenderer : function(col, fn){
5936 this.config[col].renderer = fn;
5940 * Returns the width for the specified column.
5941 * @param {Number} col The column index
5944 getColumnWidth : function(col){
5945 return this.config[col].width * 1 || this.defaultWidth;
5949 * Sets the width for a column.
5950 * @param {Number} col The column index
5951 * @param {Number} width The new width
5953 setColumnWidth : function(col, width, suppressEvent){
5954 this.config[col].width = width;
5955 this.totalWidth = null;
5957 this.fireEvent("widthchange", this, col, width);
5962 * Returns the total width of all columns.
5963 * @param {Boolean} includeHidden True to include hidden column widths
5966 getTotalWidth : function(includeHidden){
5967 if(!this.totalWidth){
5968 this.totalWidth = 0;
5969 for(var i = 0, len = this.config.length; i < len; i++){
5970 if(includeHidden || !this.isHidden(i)){
5971 this.totalWidth += this.getColumnWidth(i);
5975 return this.totalWidth;
5979 * Returns the header for the specified column.
5980 * @param {Number} col The column index
5983 getColumnHeader : function(col){
5984 return this.config[col].header;
5988 * Sets the header for a column.
5989 * @param {Number} col The column index
5990 * @param {String} header The new header
5992 setColumnHeader : function(col, header){
5993 this.config[col].header = header;
5994 this.fireEvent("headerchange", this, col, header);
5998 * Returns the tooltip for the specified column.
5999 * @param {Number} col The column index
6002 getColumnTooltip : function(col){
6003 return this.config[col].tooltip;
6006 * Sets the tooltip for a column.
6007 * @param {Number} col The column index
6008 * @param {String} tooltip The new tooltip
6010 setColumnTooltip : function(col, tooltip){
6011 this.config[col].tooltip = tooltip;
6015 * Returns the dataIndex for the specified column.
6016 * @param {Number} col The column index
6019 getDataIndex : function(col){
6020 return this.config[col].dataIndex;
6024 * Sets the dataIndex for a column.
6025 * @param {Number} col The column index
6026 * @param {Number} dataIndex The new dataIndex
6028 setDataIndex : function(col, dataIndex){
6029 this.config[col].dataIndex = dataIndex;
6035 * Returns true if the cell is editable.
6036 * @param {Number} colIndex The column index
6037 * @param {Number} rowIndex The row index - this is nto actually used..?
6040 isCellEditable : function(colIndex, rowIndex){
6041 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6045 * Returns the editor defined for the cell/column.
6046 * return false or null to disable editing.
6047 * @param {Number} colIndex The column index
6048 * @param {Number} rowIndex The row index
6051 getCellEditor : function(colIndex, rowIndex){
6052 return this.config[colIndex].editor;
6056 * Sets if a column is editable.
6057 * @param {Number} col The column index
6058 * @param {Boolean} editable True if the column is editable
6060 setEditable : function(col, editable){
6061 this.config[col].editable = editable;
6066 * Returns true if the column is hidden.
6067 * @param {Number} colIndex The column index
6070 isHidden : function(colIndex){
6071 return this.config[colIndex].hidden;
6076 * Returns true if the column width cannot be changed
6078 isFixed : function(colIndex){
6079 return this.config[colIndex].fixed;
6083 * Returns true if the column can be resized
6086 isResizable : function(colIndex){
6087 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6090 * Sets if a column is hidden.
6091 * @param {Number} colIndex The column index
6092 * @param {Boolean} hidden True if the column is hidden
6094 setHidden : function(colIndex, hidden){
6095 this.config[colIndex].hidden = hidden;
6096 this.totalWidth = null;
6097 this.fireEvent("hiddenchange", this, colIndex, hidden);
6101 * Sets the editor for a column.
6102 * @param {Number} col The column index
6103 * @param {Object} editor The editor object
6105 setEditor : function(col, editor){
6106 this.config[col].editor = editor;
6110 Roo.grid.ColumnModel.defaultRenderer = function(value)
6112 if(typeof value == "object") {
6115 if(typeof value == "string" && value.length < 1){
6119 return String.format("{0}", value);
6122 // Alias for backwards compatibility
6123 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6126 * Ext JS Library 1.1.1
6127 * Copyright(c) 2006-2007, Ext JS, LLC.
6129 * Originally Released Under LGPL - original licence link has changed is not relivant.
6132 * <script type="text/javascript">
6136 * @class Roo.LoadMask
6137 * A simple utility class for generically masking elements while loading data. If the element being masked has
6138 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6139 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6140 * element's UpdateManager load indicator and will be destroyed after the initial load.
6142 * Create a new LoadMask
6143 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6144 * @param {Object} config The config object
6146 Roo.LoadMask = function(el, config){
6147 this.el = Roo.get(el);
6148 Roo.apply(this, config);
6150 this.store.on('beforeload', this.onBeforeLoad, this);
6151 this.store.on('load', this.onLoad, this);
6152 this.store.on('loadexception', this.onLoadException, this);
6153 this.removeMask = false;
6155 var um = this.el.getUpdateManager();
6156 um.showLoadIndicator = false; // disable the default indicator
6157 um.on('beforeupdate', this.onBeforeLoad, this);
6158 um.on('update', this.onLoad, this);
6159 um.on('failure', this.onLoad, this);
6160 this.removeMask = true;
6164 Roo.LoadMask.prototype = {
6166 * @cfg {Boolean} removeMask
6167 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6168 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6172 * The text to display in a centered loading message box (defaults to 'Loading...')
6176 * @cfg {String} msgCls
6177 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6179 msgCls : 'x-mask-loading',
6182 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6188 * Disables the mask to prevent it from being displayed
6190 disable : function(){
6191 this.disabled = true;
6195 * Enables the mask so that it can be displayed
6197 enable : function(){
6198 this.disabled = false;
6201 onLoadException : function()
6205 if (typeof(arguments[3]) != 'undefined') {
6206 Roo.MessageBox.alert("Error loading",arguments[3]);
6210 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6211 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6218 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6223 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6227 onBeforeLoad : function(){
6229 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6234 destroy : function(){
6236 this.store.un('beforeload', this.onBeforeLoad, this);
6237 this.store.un('load', this.onLoad, this);
6238 this.store.un('loadexception', this.onLoadException, this);
6240 var um = this.el.getUpdateManager();
6241 um.un('beforeupdate', this.onBeforeLoad, this);
6242 um.un('update', this.onLoad, this);
6243 um.un('failure', this.onLoad, this);
6254 * @class Roo.bootstrap.Table
6255 * @extends Roo.bootstrap.Component
6256 * Bootstrap Table class
6257 * @cfg {String} cls table class
6258 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6259 * @cfg {String} bgcolor Specifies the background color for a table
6260 * @cfg {Number} border Specifies whether the table cells should have borders or not
6261 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6262 * @cfg {Number} cellspacing Specifies the space between cells
6263 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6264 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6265 * @cfg {String} sortable Specifies that the table should be sortable
6266 * @cfg {String} summary Specifies a summary of the content of a table
6267 * @cfg {Number} width Specifies the width of a table
6268 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6270 * @cfg {boolean} striped Should the rows be alternative striped
6271 * @cfg {boolean} bordered Add borders to the table
6272 * @cfg {boolean} hover Add hover highlighting
6273 * @cfg {boolean} condensed Format condensed
6274 * @cfg {boolean} responsive Format condensed
6275 * @cfg {Boolean} loadMask (true|false) default false
6276 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6277 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6278 * @cfg {Boolean} rowSelection (true|false) default false
6279 * @cfg {Boolean} cellSelection (true|false) default false
6280 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6281 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6282 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6283 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6287 * Create a new Table
6288 * @param {Object} config The config object
6291 Roo.bootstrap.Table = function(config){
6292 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6297 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6298 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6299 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6300 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6302 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6304 this.sm.grid = this;
6305 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6306 this.sm = this.selModel;
6307 this.sm.xmodule = this.xmodule || false;
6310 if (this.cm && typeof(this.cm.config) == 'undefined') {
6311 this.colModel = new Roo.grid.ColumnModel(this.cm);
6312 this.cm = this.colModel;
6313 this.cm.xmodule = this.xmodule || false;
6316 this.store= Roo.factory(this.store, Roo.data);
6317 this.ds = this.store;
6318 this.ds.xmodule = this.xmodule || false;
6321 if (this.footer && this.store) {
6322 this.footer.dataSource = this.ds;
6323 this.footer = Roo.factory(this.footer);
6330 * Fires when a cell is clicked
6331 * @param {Roo.bootstrap.Table} this
6332 * @param {Roo.Element} el
6333 * @param {Number} rowIndex
6334 * @param {Number} columnIndex
6335 * @param {Roo.EventObject} e
6339 * @event celldblclick
6340 * Fires when a cell is double clicked
6341 * @param {Roo.bootstrap.Table} this
6342 * @param {Roo.Element} el
6343 * @param {Number} rowIndex
6344 * @param {Number} columnIndex
6345 * @param {Roo.EventObject} e
6347 "celldblclick" : true,
6350 * Fires when a row is clicked
6351 * @param {Roo.bootstrap.Table} this
6352 * @param {Roo.Element} el
6353 * @param {Number} rowIndex
6354 * @param {Roo.EventObject} e
6358 * @event rowdblclick
6359 * Fires when a row is double clicked
6360 * @param {Roo.bootstrap.Table} this
6361 * @param {Roo.Element} el
6362 * @param {Number} rowIndex
6363 * @param {Roo.EventObject} e
6365 "rowdblclick" : true,
6368 * Fires when a mouseover occur
6369 * @param {Roo.bootstrap.Table} this
6370 * @param {Roo.Element} el
6371 * @param {Number} rowIndex
6372 * @param {Number} columnIndex
6373 * @param {Roo.EventObject} e
6378 * Fires when a mouseout occur
6379 * @param {Roo.bootstrap.Table} this
6380 * @param {Roo.Element} el
6381 * @param {Number} rowIndex
6382 * @param {Number} columnIndex
6383 * @param {Roo.EventObject} e
6388 * Fires when a row is rendered, so you can change add a style to it.
6389 * @param {Roo.bootstrap.Table} this
6390 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6394 * @event rowsrendered
6395 * Fires when all the rows have been rendered
6396 * @param {Roo.bootstrap.Table} this
6398 'rowsrendered' : true,
6400 * @event contextmenu
6401 * The raw contextmenu event for the entire grid.
6402 * @param {Roo.EventObject} e
6404 "contextmenu" : true,
6406 * @event rowcontextmenu
6407 * Fires when a row is right clicked
6408 * @param {Roo.bootstrap.Table} this
6409 * @param {Number} rowIndex
6410 * @param {Roo.EventObject} e
6412 "rowcontextmenu" : true,
6414 * @event cellcontextmenu
6415 * Fires when a cell is right clicked
6416 * @param {Roo.bootstrap.Table} this
6417 * @param {Number} rowIndex
6418 * @param {Number} cellIndex
6419 * @param {Roo.EventObject} e
6421 "cellcontextmenu" : true,
6423 * @event headercontextmenu
6424 * Fires when a header is right clicked
6425 * @param {Roo.bootstrap.Table} this
6426 * @param {Number} columnIndex
6427 * @param {Roo.EventObject} e
6429 "headercontextmenu" : true
6433 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6459 rowSelection : false,
6460 cellSelection : false,
6463 // Roo.Element - the tbody
6465 // Roo.Element - thead element
6468 container: false, // used by gridpanel...
6474 auto_hide_footer : false,
6476 getAutoCreate : function()
6478 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6485 if (this.scrollBody) {
6486 cfg.cls += ' table-body-fixed';
6489 cfg.cls += ' table-striped';
6493 cfg.cls += ' table-hover';
6495 if (this.bordered) {
6496 cfg.cls += ' table-bordered';
6498 if (this.condensed) {
6499 cfg.cls += ' table-condensed';
6501 if (this.responsive) {
6502 cfg.cls += ' table-responsive';
6506 cfg.cls+= ' ' +this.cls;
6509 // this lot should be simplifed...
6522 ].forEach(function(k) {
6530 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6533 if(this.store || this.cm){
6534 if(this.headerShow){
6535 cfg.cn.push(this.renderHeader());
6538 cfg.cn.push(this.renderBody());
6540 if(this.footerShow){
6541 cfg.cn.push(this.renderFooter());
6543 // where does this come from?
6544 //cfg.cls+= ' TableGrid';
6547 return { cn : [ cfg ] };
6550 initEvents : function()
6552 if(!this.store || !this.cm){
6555 if (this.selModel) {
6556 this.selModel.initEvents();
6560 //Roo.log('initEvents with ds!!!!');
6562 this.mainBody = this.el.select('tbody', true).first();
6563 this.mainHead = this.el.select('thead', true).first();
6564 this.mainFoot = this.el.select('tfoot', true).first();
6570 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6571 e.on('click', _this.sort, _this);
6574 this.mainBody.on("click", this.onClick, this);
6575 this.mainBody.on("dblclick", this.onDblClick, this);
6577 // why is this done????? = it breaks dialogs??
6578 //this.parent().el.setStyle('position', 'relative');
6582 this.footer.parentId = this.id;
6583 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6586 this.el.select('tfoot tr td').first().addClass('hide');
6591 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6594 this.store.on('load', this.onLoad, this);
6595 this.store.on('beforeload', this.onBeforeLoad, this);
6596 this.store.on('update', this.onUpdate, this);
6597 this.store.on('add', this.onAdd, this);
6598 this.store.on("clear", this.clear, this);
6600 this.el.on("contextmenu", this.onContextMenu, this);
6602 this.mainBody.on('scroll', this.onBodyScroll, this);
6604 this.cm.on("headerchange", this.onHeaderChange, this);
6606 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6610 onContextMenu : function(e, t)
6612 this.processEvent("contextmenu", e);
6615 processEvent : function(name, e)
6617 if (name != 'touchstart' ) {
6618 this.fireEvent(name, e);
6621 var t = e.getTarget();
6623 var cell = Roo.get(t);
6629 if(cell.findParent('tfoot', false, true)){
6633 if(cell.findParent('thead', false, true)){
6635 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6636 cell = Roo.get(t).findParent('th', false, true);
6638 Roo.log("failed to find th in thead?");
6639 Roo.log(e.getTarget());
6644 var cellIndex = cell.dom.cellIndex;
6646 var ename = name == 'touchstart' ? 'click' : name;
6647 this.fireEvent("header" + ename, this, cellIndex, e);
6652 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6653 cell = Roo.get(t).findParent('td', false, true);
6655 Roo.log("failed to find th in tbody?");
6656 Roo.log(e.getTarget());
6661 var row = cell.findParent('tr', false, true);
6662 var cellIndex = cell.dom.cellIndex;
6663 var rowIndex = row.dom.rowIndex - 1;
6667 this.fireEvent("row" + name, this, rowIndex, e);
6671 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6677 onMouseover : function(e, el)
6679 var cell = Roo.get(el);
6685 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6686 cell = cell.findParent('td', false, true);
6689 var row = cell.findParent('tr', false, true);
6690 var cellIndex = cell.dom.cellIndex;
6691 var rowIndex = row.dom.rowIndex - 1; // start from 0
6693 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6697 onMouseout : function(e, el)
6699 var cell = Roo.get(el);
6705 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6706 cell = cell.findParent('td', false, true);
6709 var row = cell.findParent('tr', false, true);
6710 var cellIndex = cell.dom.cellIndex;
6711 var rowIndex = row.dom.rowIndex - 1; // start from 0
6713 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6717 onClick : function(e, el)
6719 var cell = Roo.get(el);
6721 if(!cell || (!this.cellSelection && !this.rowSelection)){
6725 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6726 cell = cell.findParent('td', false, true);
6729 if(!cell || typeof(cell) == 'undefined'){
6733 var row = cell.findParent('tr', false, true);
6735 if(!row || typeof(row) == 'undefined'){
6739 var cellIndex = cell.dom.cellIndex;
6740 var rowIndex = this.getRowIndex(row);
6742 // why??? - should these not be based on SelectionModel?
6743 if(this.cellSelection){
6744 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6747 if(this.rowSelection){
6748 this.fireEvent('rowclick', this, row, rowIndex, e);
6754 onDblClick : function(e,el)
6756 var cell = Roo.get(el);
6758 if(!cell || (!this.cellSelection && !this.rowSelection)){
6762 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6763 cell = cell.findParent('td', false, true);
6766 if(!cell || typeof(cell) == 'undefined'){
6770 var row = cell.findParent('tr', false, true);
6772 if(!row || typeof(row) == 'undefined'){
6776 var cellIndex = cell.dom.cellIndex;
6777 var rowIndex = this.getRowIndex(row);
6779 if(this.cellSelection){
6780 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6783 if(this.rowSelection){
6784 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6788 sort : function(e,el)
6790 var col = Roo.get(el);
6792 if(!col.hasClass('sortable')){
6796 var sort = col.attr('sort');
6799 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6803 this.store.sortInfo = {field : sort, direction : dir};
6806 Roo.log("calling footer first");
6807 this.footer.onClick('first');
6810 this.store.load({ params : { start : 0 } });
6814 renderHeader : function()
6822 this.totalWidth = 0;
6824 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6826 var config = cm.config[i];
6830 cls : 'x-hcol-' + i,
6832 html: cm.getColumnHeader(i)
6837 if(typeof(config.sortable) != 'undefined' && config.sortable){
6839 c.html = '<i class="glyphicon"></i>' + c.html;
6842 // could use BS4 hidden-..-down
6844 if(typeof(config.lgHeader) != 'undefined'){
6845 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
6848 if(typeof(config.mdHeader) != 'undefined'){
6849 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6852 if(typeof(config.smHeader) != 'undefined'){
6853 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6856 if(typeof(config.xsHeader) != 'undefined'){
6857 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6864 if(typeof(config.tooltip) != 'undefined'){
6865 c.tooltip = config.tooltip;
6868 if(typeof(config.colspan) != 'undefined'){
6869 c.colspan = config.colspan;
6872 if(typeof(config.hidden) != 'undefined' && config.hidden){
6873 c.style += ' display:none;';
6876 if(typeof(config.dataIndex) != 'undefined'){
6877 c.sort = config.dataIndex;
6882 if(typeof(config.align) != 'undefined' && config.align.length){
6883 c.style += ' text-align:' + config.align + ';';
6886 if(typeof(config.width) != 'undefined'){
6887 c.style += ' width:' + config.width + 'px;';
6888 this.totalWidth += config.width;
6890 this.totalWidth += 100; // assume minimum of 100 per column?
6893 if(typeof(config.cls) != 'undefined'){
6894 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6897 ['xs','sm','md','lg'].map(function(size){
6899 if(typeof(config[size]) == 'undefined'){
6903 if (!config[size]) { // 0 = hidden
6904 // BS 4 '0' is treated as hide that column and below.
6905 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
6909 c.cls += ' col-' + size + '-' + config[size] + (
6910 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
6922 renderBody : function()
6932 colspan : this.cm.getColumnCount()
6942 renderFooter : function()
6952 colspan : this.cm.getColumnCount()
6966 // Roo.log('ds onload');
6971 var ds = this.store;
6973 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6974 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6975 if (_this.store.sortInfo) {
6977 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6978 e.select('i', true).addClass(['glyphicon-arrow-up']);
6981 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6982 e.select('i', true).addClass(['glyphicon-arrow-down']);
6987 var tbody = this.mainBody;
6989 if(ds.getCount() > 0){
6990 ds.data.each(function(d,rowIndex){
6991 var row = this.renderRow(cm, ds, rowIndex);
6993 tbody.createChild(row);
6997 if(row.cellObjects.length){
6998 Roo.each(row.cellObjects, function(r){
6999 _this.renderCellObject(r);
7006 var tfoot = this.el.select('tfoot', true).first();
7008 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7010 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7012 var total = this.ds.getTotalCount();
7014 if(this.footer.pageSize < total){
7015 this.mainFoot.show();
7019 Roo.each(this.el.select('tbody td', true).elements, function(e){
7020 e.on('mouseover', _this.onMouseover, _this);
7023 Roo.each(this.el.select('tbody td', true).elements, function(e){
7024 e.on('mouseout', _this.onMouseout, _this);
7026 this.fireEvent('rowsrendered', this);
7032 onUpdate : function(ds,record)
7034 this.refreshRow(record);
7038 onRemove : function(ds, record, index, isUpdate){
7039 if(isUpdate !== true){
7040 this.fireEvent("beforerowremoved", this, index, record);
7042 var bt = this.mainBody.dom;
7044 var rows = this.el.select('tbody > tr', true).elements;
7046 if(typeof(rows[index]) != 'undefined'){
7047 bt.removeChild(rows[index].dom);
7050 // if(bt.rows[index]){
7051 // bt.removeChild(bt.rows[index]);
7054 if(isUpdate !== true){
7055 //this.stripeRows(index);
7056 //this.syncRowHeights(index, index);
7058 this.fireEvent("rowremoved", this, index, record);
7062 onAdd : function(ds, records, rowIndex)
7064 //Roo.log('on Add called');
7065 // - note this does not handle multiple adding very well..
7066 var bt = this.mainBody.dom;
7067 for (var i =0 ; i < records.length;i++) {
7068 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7069 //Roo.log(records[i]);
7070 //Roo.log(this.store.getAt(rowIndex+i));
7071 this.insertRow(this.store, rowIndex + i, false);
7078 refreshRow : function(record){
7079 var ds = this.store, index;
7080 if(typeof record == 'number'){
7082 record = ds.getAt(index);
7084 index = ds.indexOf(record);
7086 this.insertRow(ds, index, true);
7088 this.onRemove(ds, record, index+1, true);
7090 //this.syncRowHeights(index, index);
7092 this.fireEvent("rowupdated", this, index, record);
7095 insertRow : function(dm, rowIndex, isUpdate){
7098 this.fireEvent("beforerowsinserted", this, rowIndex);
7100 //var s = this.getScrollState();
7101 var row = this.renderRow(this.cm, this.store, rowIndex);
7102 // insert before rowIndex..
7103 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7107 if(row.cellObjects.length){
7108 Roo.each(row.cellObjects, function(r){
7109 _this.renderCellObject(r);
7114 this.fireEvent("rowsinserted", this, rowIndex);
7115 //this.syncRowHeights(firstRow, lastRow);
7116 //this.stripeRows(firstRow);
7123 getRowDom : function(rowIndex)
7125 var rows = this.el.select('tbody > tr', true).elements;
7127 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7130 // returns the object tree for a tr..
7133 renderRow : function(cm, ds, rowIndex)
7135 var d = ds.getAt(rowIndex);
7139 cls : 'x-row-' + rowIndex,
7143 var cellObjects = [];
7145 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7146 var config = cm.config[i];
7148 var renderer = cm.getRenderer(i);
7152 if(typeof(renderer) !== 'undefined'){
7153 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7155 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7156 // and are rendered into the cells after the row is rendered - using the id for the element.
7158 if(typeof(value) === 'object'){
7168 rowIndex : rowIndex,
7173 this.fireEvent('rowclass', this, rowcfg);
7177 cls : rowcfg.rowClass + ' x-col-' + i,
7179 html: (typeof(value) === 'object') ? '' : value
7186 if(typeof(config.colspan) != 'undefined'){
7187 td.colspan = config.colspan;
7190 if(typeof(config.hidden) != 'undefined' && config.hidden){
7191 td.style += ' display:none;';
7194 if(typeof(config.align) != 'undefined' && config.align.length){
7195 td.style += ' text-align:' + config.align + ';';
7197 if(typeof(config.valign) != 'undefined' && config.valign.length){
7198 td.style += ' vertical-align:' + config.valign + ';';
7201 if(typeof(config.width) != 'undefined'){
7202 td.style += ' width:' + config.width + 'px;';
7205 if(typeof(config.cursor) != 'undefined'){
7206 td.style += ' cursor:' + config.cursor + ';';
7209 if(typeof(config.cls) != 'undefined'){
7210 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7213 ['xs','sm','md','lg'].map(function(size){
7215 if(typeof(config[size]) == 'undefined'){
7221 if (!config[size]) { // 0 = hidden
7222 // BS 4 '0' is treated as hide that column and below.
7223 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
7227 td.cls += ' col-' + size + '-' + config[size] + (
7228 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7238 row.cellObjects = cellObjects;
7246 onBeforeLoad : function()
7255 this.el.select('tbody', true).first().dom.innerHTML = '';
7258 * Show or hide a row.
7259 * @param {Number} rowIndex to show or hide
7260 * @param {Boolean} state hide
7262 setRowVisibility : function(rowIndex, state)
7264 var bt = this.mainBody.dom;
7266 var rows = this.el.select('tbody > tr', true).elements;
7268 if(typeof(rows[rowIndex]) == 'undefined'){
7271 rows[rowIndex].dom.style.display = state ? '' : 'none';
7275 getSelectionModel : function(){
7277 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7279 return this.selModel;
7282 * Render the Roo.bootstrap object from renderder
7284 renderCellObject : function(r)
7288 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7290 var t = r.cfg.render(r.container);
7293 Roo.each(r.cfg.cn, function(c){
7295 container: t.getChildContainer(),
7298 _this.renderCellObject(child);
7303 getRowIndex : function(row)
7307 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7318 * Returns the grid's underlying element = used by panel.Grid
7319 * @return {Element} The element
7321 getGridEl : function(){
7325 * Forces a resize - used by panel.Grid
7326 * @return {Element} The element
7328 autoSize : function()
7330 //var ctr = Roo.get(this.container.dom.parentElement);
7331 var ctr = Roo.get(this.el.dom);
7333 var thd = this.getGridEl().select('thead',true).first();
7334 var tbd = this.getGridEl().select('tbody', true).first();
7335 var tfd = this.getGridEl().select('tfoot', true).first();
7337 var cw = ctr.getWidth();
7341 tbd.setSize(ctr.getWidth(),
7342 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7344 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7347 cw = Math.max(cw, this.totalWidth);
7348 this.getGridEl().select('tr',true).setWidth(cw);
7349 // resize 'expandable coloumn?
7351 return; // we doe not have a view in this design..
7354 onBodyScroll: function()
7356 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7358 this.mainHead.setStyle({
7359 'position' : 'relative',
7360 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7366 var scrollHeight = this.mainBody.dom.scrollHeight;
7368 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7370 var height = this.mainBody.getHeight();
7372 if(scrollHeight - height == scrollTop) {
7374 var total = this.ds.getTotalCount();
7376 if(this.footer.cursor + this.footer.pageSize < total){
7378 this.footer.ds.load({
7380 start : this.footer.cursor + this.footer.pageSize,
7381 limit : this.footer.pageSize
7391 onHeaderChange : function()
7393 var header = this.renderHeader();
7394 var table = this.el.select('table', true).first();
7396 this.mainHead.remove();
7397 this.mainHead = table.createChild(header, this.mainBody, false);
7400 onHiddenChange : function(colModel, colIndex, hidden)
7402 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7403 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7405 this.CSS.updateRule(thSelector, "display", "");
7406 this.CSS.updateRule(tdSelector, "display", "");
7409 this.CSS.updateRule(thSelector, "display", "none");
7410 this.CSS.updateRule(tdSelector, "display", "none");
7413 this.onHeaderChange();
7417 setColumnWidth: function(col_index, width)
7419 // width = "md-2 xs-2..."
7420 if(!this.colModel.config[col_index]) {
7424 var w = width.split(" ");
7426 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7428 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7431 for(var j = 0; j < w.length; j++) {
7437 var size_cls = w[j].split("-");
7439 if(!Number.isInteger(size_cls[1] * 1)) {
7443 if(!this.colModel.config[col_index][size_cls[0]]) {
7447 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7451 h_row[0].classList.replace(
7452 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7453 "col-"+size_cls[0]+"-"+size_cls[1]
7456 for(var i = 0; i < rows.length; i++) {
7458 var size_cls = w[j].split("-");
7460 if(!Number.isInteger(size_cls[1] * 1)) {
7464 if(!this.colModel.config[col_index][size_cls[0]]) {
7468 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7472 rows[i].classList.replace(
7473 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7474 "col-"+size_cls[0]+"-"+size_cls[1]
7478 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7493 * @class Roo.bootstrap.TableCell
7494 * @extends Roo.bootstrap.Component
7495 * Bootstrap TableCell class
7496 * @cfg {String} html cell contain text
7497 * @cfg {String} cls cell class
7498 * @cfg {String} tag cell tag (td|th) default td
7499 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7500 * @cfg {String} align Aligns the content in a cell
7501 * @cfg {String} axis Categorizes cells
7502 * @cfg {String} bgcolor Specifies the background color of a cell
7503 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7504 * @cfg {Number} colspan Specifies the number of columns a cell should span
7505 * @cfg {String} headers Specifies one or more header cells a cell is related to
7506 * @cfg {Number} height Sets the height of a cell
7507 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7508 * @cfg {Number} rowspan Sets the number of rows a cell should span
7509 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7510 * @cfg {String} valign Vertical aligns the content in a cell
7511 * @cfg {Number} width Specifies the width of a cell
7514 * Create a new TableCell
7515 * @param {Object} config The config object
7518 Roo.bootstrap.TableCell = function(config){
7519 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7522 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7542 getAutoCreate : function(){
7543 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7563 cfg.align=this.align
7569 cfg.bgcolor=this.bgcolor
7572 cfg.charoff=this.charoff
7575 cfg.colspan=this.colspan
7578 cfg.headers=this.headers
7581 cfg.height=this.height
7584 cfg.nowrap=this.nowrap
7587 cfg.rowspan=this.rowspan
7590 cfg.scope=this.scope
7593 cfg.valign=this.valign
7596 cfg.width=this.width
7615 * @class Roo.bootstrap.TableRow
7616 * @extends Roo.bootstrap.Component
7617 * Bootstrap TableRow class
7618 * @cfg {String} cls row class
7619 * @cfg {String} align Aligns the content in a table row
7620 * @cfg {String} bgcolor Specifies a background color for a table row
7621 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7622 * @cfg {String} valign Vertical aligns the content in a table row
7625 * Create a new TableRow
7626 * @param {Object} config The config object
7629 Roo.bootstrap.TableRow = function(config){
7630 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7633 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7641 getAutoCreate : function(){
7642 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7652 cfg.align = this.align;
7655 cfg.bgcolor = this.bgcolor;
7658 cfg.charoff = this.charoff;
7661 cfg.valign = this.valign;
7679 * @class Roo.bootstrap.TableBody
7680 * @extends Roo.bootstrap.Component
7681 * Bootstrap TableBody class
7682 * @cfg {String} cls element class
7683 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7684 * @cfg {String} align Aligns the content inside the element
7685 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7686 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7689 * Create a new TableBody
7690 * @param {Object} config The config object
7693 Roo.bootstrap.TableBody = function(config){
7694 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7697 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7705 getAutoCreate : function(){
7706 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7720 cfg.align = this.align;
7723 cfg.charoff = this.charoff;
7726 cfg.valign = this.valign;
7733 // initEvents : function()
7740 // this.store = Roo.factory(this.store, Roo.data);
7741 // this.store.on('load', this.onLoad, this);
7743 // this.store.load();
7747 // onLoad: function ()
7749 // this.fireEvent('load', this);
7759 * Ext JS Library 1.1.1
7760 * Copyright(c) 2006-2007, Ext JS, LLC.
7762 * Originally Released Under LGPL - original licence link has changed is not relivant.
7765 * <script type="text/javascript">
7768 // as we use this in bootstrap.
7769 Roo.namespace('Roo.form');
7771 * @class Roo.form.Action
7772 * Internal Class used to handle form actions
7774 * @param {Roo.form.BasicForm} el The form element or its id
7775 * @param {Object} config Configuration options
7780 // define the action interface
7781 Roo.form.Action = function(form, options){
7783 this.options = options || {};
7786 * Client Validation Failed
7789 Roo.form.Action.CLIENT_INVALID = 'client';
7791 * Server Validation Failed
7794 Roo.form.Action.SERVER_INVALID = 'server';
7796 * Connect to Server Failed
7799 Roo.form.Action.CONNECT_FAILURE = 'connect';
7801 * Reading Data from Server Failed
7804 Roo.form.Action.LOAD_FAILURE = 'load';
7806 Roo.form.Action.prototype = {
7808 failureType : undefined,
7809 response : undefined,
7813 run : function(options){
7818 success : function(response){
7823 handleResponse : function(response){
7827 // default connection failure
7828 failure : function(response){
7830 this.response = response;
7831 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7832 this.form.afterAction(this, false);
7835 processResponse : function(response){
7836 this.response = response;
7837 if(!response.responseText){
7840 this.result = this.handleResponse(response);
7844 // utility functions used internally
7845 getUrl : function(appendParams){
7846 var url = this.options.url || this.form.url || this.form.el.dom.action;
7848 var p = this.getParams();
7850 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7856 getMethod : function(){
7857 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7860 getParams : function(){
7861 var bp = this.form.baseParams;
7862 var p = this.options.params;
7864 if(typeof p == "object"){
7865 p = Roo.urlEncode(Roo.applyIf(p, bp));
7866 }else if(typeof p == 'string' && bp){
7867 p += '&' + Roo.urlEncode(bp);
7870 p = Roo.urlEncode(bp);
7875 createCallback : function(){
7877 success: this.success,
7878 failure: this.failure,
7880 timeout: (this.form.timeout*1000),
7881 upload: this.form.fileUpload ? this.success : undefined
7886 Roo.form.Action.Submit = function(form, options){
7887 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7890 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7893 haveProgress : false,
7894 uploadComplete : false,
7896 // uploadProgress indicator.
7897 uploadProgress : function()
7899 if (!this.form.progressUrl) {
7903 if (!this.haveProgress) {
7904 Roo.MessageBox.progress("Uploading", "Uploading");
7906 if (this.uploadComplete) {
7907 Roo.MessageBox.hide();
7911 this.haveProgress = true;
7913 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7915 var c = new Roo.data.Connection();
7917 url : this.form.progressUrl,
7922 success : function(req){
7923 //console.log(data);
7927 rdata = Roo.decode(req.responseText)
7929 Roo.log("Invalid data from server..");
7933 if (!rdata || !rdata.success) {
7935 Roo.MessageBox.alert(Roo.encode(rdata));
7938 var data = rdata.data;
7940 if (this.uploadComplete) {
7941 Roo.MessageBox.hide();
7946 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7947 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7950 this.uploadProgress.defer(2000,this);
7953 failure: function(data) {
7954 Roo.log('progress url failed ');
7965 // run get Values on the form, so it syncs any secondary forms.
7966 this.form.getValues();
7968 var o = this.options;
7969 var method = this.getMethod();
7970 var isPost = method == 'POST';
7971 if(o.clientValidation === false || this.form.isValid()){
7973 if (this.form.progressUrl) {
7974 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7975 (new Date() * 1) + '' + Math.random());
7980 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7981 form:this.form.el.dom,
7982 url:this.getUrl(!isPost),
7984 params:isPost ? this.getParams() : null,
7985 isUpload: this.form.fileUpload,
7986 formData : this.form.formData
7989 this.uploadProgress();
7991 }else if (o.clientValidation !== false){ // client validation failed
7992 this.failureType = Roo.form.Action.CLIENT_INVALID;
7993 this.form.afterAction(this, false);
7997 success : function(response)
7999 this.uploadComplete= true;
8000 if (this.haveProgress) {
8001 Roo.MessageBox.hide();
8005 var result = this.processResponse(response);
8006 if(result === true || result.success){
8007 this.form.afterAction(this, true);
8011 this.form.markInvalid(result.errors);
8012 this.failureType = Roo.form.Action.SERVER_INVALID;
8014 this.form.afterAction(this, false);
8016 failure : function(response)
8018 this.uploadComplete= true;
8019 if (this.haveProgress) {
8020 Roo.MessageBox.hide();
8023 this.response = response;
8024 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8025 this.form.afterAction(this, false);
8028 handleResponse : function(response){
8029 if(this.form.errorReader){
8030 var rs = this.form.errorReader.read(response);
8033 for(var i = 0, len = rs.records.length; i < len; i++) {
8034 var r = rs.records[i];
8038 if(errors.length < 1){
8042 success : rs.success,
8048 ret = Roo.decode(response.responseText);
8052 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8062 Roo.form.Action.Load = function(form, options){
8063 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8064 this.reader = this.form.reader;
8067 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8072 Roo.Ajax.request(Roo.apply(
8073 this.createCallback(), {
8074 method:this.getMethod(),
8075 url:this.getUrl(false),
8076 params:this.getParams()
8080 success : function(response){
8082 var result = this.processResponse(response);
8083 if(result === true || !result.success || !result.data){
8084 this.failureType = Roo.form.Action.LOAD_FAILURE;
8085 this.form.afterAction(this, false);
8088 this.form.clearInvalid();
8089 this.form.setValues(result.data);
8090 this.form.afterAction(this, true);
8093 handleResponse : function(response){
8094 if(this.form.reader){
8095 var rs = this.form.reader.read(response);
8096 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8098 success : rs.success,
8102 return Roo.decode(response.responseText);
8106 Roo.form.Action.ACTION_TYPES = {
8107 'load' : Roo.form.Action.Load,
8108 'submit' : Roo.form.Action.Submit
8117 * @class Roo.bootstrap.Form
8118 * @extends Roo.bootstrap.Component
8119 * Bootstrap Form class
8120 * @cfg {String} method GET | POST (default POST)
8121 * @cfg {String} labelAlign top | left (default top)
8122 * @cfg {String} align left | right - for navbars
8123 * @cfg {Boolean} loadMask load mask when submit (default true)
8128 * @param {Object} config The config object
8132 Roo.bootstrap.Form = function(config){
8134 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8136 Roo.bootstrap.Form.popover.apply();
8140 * @event clientvalidation
8141 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8142 * @param {Form} this
8143 * @param {Boolean} valid true if the form has passed client-side validation
8145 clientvalidation: true,
8147 * @event beforeaction
8148 * Fires before any action is performed. Return false to cancel the action.
8149 * @param {Form} this
8150 * @param {Action} action The action to be performed
8154 * @event actionfailed
8155 * Fires when an action fails.
8156 * @param {Form} this
8157 * @param {Action} action The action that failed
8159 actionfailed : true,
8161 * @event actioncomplete
8162 * Fires when an action is completed.
8163 * @param {Form} this
8164 * @param {Action} action The action that completed
8166 actioncomplete : true
8170 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8173 * @cfg {String} method
8174 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8179 * The URL to use for form actions if one isn't supplied in the action options.
8182 * @cfg {Boolean} fileUpload
8183 * Set to true if this form is a file upload.
8187 * @cfg {Object} baseParams
8188 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8192 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8196 * @cfg {Sting} align (left|right) for navbar forms
8201 activeAction : null,
8204 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8205 * element by passing it or its id or mask the form itself by passing in true.
8208 waitMsgTarget : false,
8213 * @cfg {Boolean} errorMask (true|false) default false
8218 * @cfg {Number} maskOffset Default 100
8223 * @cfg {Boolean} maskBody
8227 getAutoCreate : function(){
8231 method : this.method || 'POST',
8232 id : this.id || Roo.id(),
8235 if (this.parent().xtype.match(/^Nav/)) {
8236 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8240 if (this.labelAlign == 'left' ) {
8241 cfg.cls += ' form-horizontal';
8247 initEvents : function()
8249 this.el.on('submit', this.onSubmit, this);
8250 // this was added as random key presses on the form where triggering form submit.
8251 this.el.on('keypress', function(e) {
8252 if (e.getCharCode() != 13) {
8255 // we might need to allow it for textareas.. and some other items.
8256 // check e.getTarget().
8258 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8262 Roo.log("keypress blocked");
8270 onSubmit : function(e){
8275 * Returns true if client-side validation on the form is successful.
8278 isValid : function(){
8279 var items = this.getItems();
8283 items.each(function(f){
8289 Roo.log('invalid field: ' + f.name);
8293 if(!target && f.el.isVisible(true)){
8299 if(this.errorMask && !valid){
8300 Roo.bootstrap.Form.popover.mask(this, target);
8307 * Returns true if any fields in this form have changed since their original load.
8310 isDirty : function(){
8312 var items = this.getItems();
8313 items.each(function(f){
8323 * Performs a predefined action (submit or load) or custom actions you define on this form.
8324 * @param {String} actionName The name of the action type
8325 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8326 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8327 * accept other config options):
8329 Property Type Description
8330 ---------------- --------------- ----------------------------------------------------------------------------------
8331 url String The url for the action (defaults to the form's url)
8332 method String The form method to use (defaults to the form's method, or POST if not defined)
8333 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8334 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8335 validate the form on the client (defaults to false)
8337 * @return {BasicForm} this
8339 doAction : function(action, options){
8340 if(typeof action == 'string'){
8341 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8343 if(this.fireEvent('beforeaction', this, action) !== false){
8344 this.beforeAction(action);
8345 action.run.defer(100, action);
8351 beforeAction : function(action){
8352 var o = action.options;
8357 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8359 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8362 // not really supported yet.. ??
8364 //if(this.waitMsgTarget === true){
8365 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8366 //}else if(this.waitMsgTarget){
8367 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8368 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8370 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8376 afterAction : function(action, success){
8377 this.activeAction = null;
8378 var o = action.options;
8383 Roo.get(document.body).unmask();
8389 //if(this.waitMsgTarget === true){
8390 // this.el.unmask();
8391 //}else if(this.waitMsgTarget){
8392 // this.waitMsgTarget.unmask();
8394 // Roo.MessageBox.updateProgress(1);
8395 // Roo.MessageBox.hide();
8402 Roo.callback(o.success, o.scope, [this, action]);
8403 this.fireEvent('actioncomplete', this, action);
8407 // failure condition..
8408 // we have a scenario where updates need confirming.
8409 // eg. if a locking scenario exists..
8410 // we look for { errors : { needs_confirm : true }} in the response.
8412 (typeof(action.result) != 'undefined') &&
8413 (typeof(action.result.errors) != 'undefined') &&
8414 (typeof(action.result.errors.needs_confirm) != 'undefined')
8417 Roo.log("not supported yet");
8420 Roo.MessageBox.confirm(
8421 "Change requires confirmation",
8422 action.result.errorMsg,
8427 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8437 Roo.callback(o.failure, o.scope, [this, action]);
8438 // show an error message if no failed handler is set..
8439 if (!this.hasListener('actionfailed')) {
8440 Roo.log("need to add dialog support");
8442 Roo.MessageBox.alert("Error",
8443 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8444 action.result.errorMsg :
8445 "Saving Failed, please check your entries or try again"
8450 this.fireEvent('actionfailed', this, action);
8455 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8456 * @param {String} id The value to search for
8459 findField : function(id){
8460 var items = this.getItems();
8461 var field = items.get(id);
8463 items.each(function(f){
8464 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8471 return field || null;
8474 * Mark fields in this form invalid in bulk.
8475 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8476 * @return {BasicForm} this
8478 markInvalid : function(errors){
8479 if(errors instanceof Array){
8480 for(var i = 0, len = errors.length; i < len; i++){
8481 var fieldError = errors[i];
8482 var f = this.findField(fieldError.id);
8484 f.markInvalid(fieldError.msg);
8490 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8491 field.markInvalid(errors[id]);
8495 //Roo.each(this.childForms || [], function (f) {
8496 // f.markInvalid(errors);
8503 * Set values for fields in this form in bulk.
8504 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8505 * @return {BasicForm} this
8507 setValues : function(values){
8508 if(values instanceof Array){ // array of objects
8509 for(var i = 0, len = values.length; i < len; i++){
8511 var f = this.findField(v.id);
8513 f.setValue(v.value);
8514 if(this.trackResetOnLoad){
8515 f.originalValue = f.getValue();
8519 }else{ // object hash
8522 if(typeof values[id] != 'function' && (field = this.findField(id))){
8524 if (field.setFromData &&
8526 field.displayField &&
8527 // combos' with local stores can
8528 // be queried via setValue()
8529 // to set their value..
8530 (field.store && !field.store.isLocal)
8534 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8535 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8536 field.setFromData(sd);
8538 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8540 field.setFromData(values);
8543 field.setValue(values[id]);
8547 if(this.trackResetOnLoad){
8548 field.originalValue = field.getValue();
8554 //Roo.each(this.childForms || [], function (f) {
8555 // f.setValues(values);
8562 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8563 * they are returned as an array.
8564 * @param {Boolean} asString
8567 getValues : function(asString){
8568 //if (this.childForms) {
8569 // copy values from the child forms
8570 // Roo.each(this.childForms, function (f) {
8571 // this.setValues(f.getValues());
8577 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8578 if(asString === true){
8581 return Roo.urlDecode(fs);
8585 * Returns the fields in this form as an object with key/value pairs.
8586 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8589 getFieldValues : function(with_hidden)
8591 var items = this.getItems();
8593 items.each(function(f){
8599 var v = f.getValue();
8601 if (f.inputType =='radio') {
8602 if (typeof(ret[f.getName()]) == 'undefined') {
8603 ret[f.getName()] = ''; // empty..
8606 if (!f.el.dom.checked) {
8614 if(f.xtype == 'MoneyField'){
8615 ret[f.currencyName] = f.getCurrency();
8618 // not sure if this supported any more..
8619 if ((typeof(v) == 'object') && f.getRawValue) {
8620 v = f.getRawValue() ; // dates..
8622 // combo boxes where name != hiddenName...
8623 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8624 ret[f.name] = f.getRawValue();
8626 ret[f.getName()] = v;
8633 * Clears all invalid messages in this form.
8634 * @return {BasicForm} this
8636 clearInvalid : function(){
8637 var items = this.getItems();
8639 items.each(function(f){
8648 * @return {BasicForm} this
8651 var items = this.getItems();
8652 items.each(function(f){
8656 Roo.each(this.childForms || [], function (f) {
8664 getItems : function()
8666 var r=new Roo.util.MixedCollection(false, function(o){
8667 return o.id || (o.id = Roo.id());
8669 var iter = function(el) {
8676 Roo.each(el.items,function(e) {
8685 hideFields : function(items)
8687 Roo.each(items, function(i){
8689 var f = this.findField(i);
8700 showFields : function(items)
8702 Roo.each(items, function(i){
8704 var f = this.findField(i);
8717 Roo.apply(Roo.bootstrap.Form, {
8744 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8745 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8746 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8747 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8750 this.maskEl.top.enableDisplayMode("block");
8751 this.maskEl.left.enableDisplayMode("block");
8752 this.maskEl.bottom.enableDisplayMode("block");
8753 this.maskEl.right.enableDisplayMode("block");
8755 this.toolTip = new Roo.bootstrap.Tooltip({
8756 cls : 'roo-form-error-popover',
8758 'left' : ['r-l', [-2,0], 'right'],
8759 'right' : ['l-r', [2,0], 'left'],
8760 'bottom' : ['tl-bl', [0,2], 'top'],
8761 'top' : [ 'bl-tl', [0,-2], 'bottom']
8765 this.toolTip.render(Roo.get(document.body));
8767 this.toolTip.el.enableDisplayMode("block");
8769 Roo.get(document.body).on('click', function(){
8773 Roo.get(document.body).on('touchstart', function(){
8777 this.isApplied = true
8780 mask : function(form, target)
8784 this.target = target;
8786 if(!this.form.errorMask || !target.el){
8790 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8792 Roo.log(scrollable);
8794 var ot = this.target.el.calcOffsetsTo(scrollable);
8796 var scrollTo = ot[1] - this.form.maskOffset;
8798 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8800 scrollable.scrollTo('top', scrollTo);
8802 var box = this.target.el.getBox();
8804 var zIndex = Roo.bootstrap.Modal.zIndex++;
8807 this.maskEl.top.setStyle('position', 'absolute');
8808 this.maskEl.top.setStyle('z-index', zIndex);
8809 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8810 this.maskEl.top.setLeft(0);
8811 this.maskEl.top.setTop(0);
8812 this.maskEl.top.show();
8814 this.maskEl.left.setStyle('position', 'absolute');
8815 this.maskEl.left.setStyle('z-index', zIndex);
8816 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8817 this.maskEl.left.setLeft(0);
8818 this.maskEl.left.setTop(box.y - this.padding);
8819 this.maskEl.left.show();
8821 this.maskEl.bottom.setStyle('position', 'absolute');
8822 this.maskEl.bottom.setStyle('z-index', zIndex);
8823 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8824 this.maskEl.bottom.setLeft(0);
8825 this.maskEl.bottom.setTop(box.bottom + this.padding);
8826 this.maskEl.bottom.show();
8828 this.maskEl.right.setStyle('position', 'absolute');
8829 this.maskEl.right.setStyle('z-index', zIndex);
8830 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8831 this.maskEl.right.setLeft(box.right + this.padding);
8832 this.maskEl.right.setTop(box.y - this.padding);
8833 this.maskEl.right.show();
8835 this.toolTip.bindEl = this.target.el;
8837 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8839 var tip = this.target.blankText;
8841 if(this.target.getValue() !== '' ) {
8843 if (this.target.invalidText.length) {
8844 tip = this.target.invalidText;
8845 } else if (this.target.regexText.length){
8846 tip = this.target.regexText;
8850 this.toolTip.show(tip);
8852 this.intervalID = window.setInterval(function() {
8853 Roo.bootstrap.Form.popover.unmask();
8856 window.onwheel = function(){ return false;};
8858 (function(){ this.isMasked = true; }).defer(500, this);
8864 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8868 this.maskEl.top.setStyle('position', 'absolute');
8869 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8870 this.maskEl.top.hide();
8872 this.maskEl.left.setStyle('position', 'absolute');
8873 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8874 this.maskEl.left.hide();
8876 this.maskEl.bottom.setStyle('position', 'absolute');
8877 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8878 this.maskEl.bottom.hide();
8880 this.maskEl.right.setStyle('position', 'absolute');
8881 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8882 this.maskEl.right.hide();
8884 this.toolTip.hide();
8886 this.toolTip.el.hide();
8888 window.onwheel = function(){ return true;};
8890 if(this.intervalID){
8891 window.clearInterval(this.intervalID);
8892 this.intervalID = false;
8895 this.isMasked = false;
8905 * Ext JS Library 1.1.1
8906 * Copyright(c) 2006-2007, Ext JS, LLC.
8908 * Originally Released Under LGPL - original licence link has changed is not relivant.
8911 * <script type="text/javascript">
8914 * @class Roo.form.VTypes
8915 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8918 Roo.form.VTypes = function(){
8919 // closure these in so they are only created once.
8920 var alpha = /^[a-zA-Z_]+$/;
8921 var alphanum = /^[a-zA-Z0-9_]+$/;
8922 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8923 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8925 // All these messages and functions are configurable
8928 * The function used to validate email addresses
8929 * @param {String} value The email address
8931 'email' : function(v){
8932 return email.test(v);
8935 * The error text to display when the email validation function returns false
8938 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8940 * The keystroke filter mask to be applied on email input
8943 'emailMask' : /[a-z0-9_\.\-@]/i,
8946 * The function used to validate URLs
8947 * @param {String} value The URL
8949 'url' : function(v){
8953 * The error text to display when the url validation function returns false
8956 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8959 * The function used to validate alpha values
8960 * @param {String} value The value
8962 'alpha' : function(v){
8963 return alpha.test(v);
8966 * The error text to display when the alpha validation function returns false
8969 'alphaText' : 'This field should only contain letters and _',
8971 * The keystroke filter mask to be applied on alpha input
8974 'alphaMask' : /[a-z_]/i,
8977 * The function used to validate alphanumeric values
8978 * @param {String} value The value
8980 'alphanum' : function(v){
8981 return alphanum.test(v);
8984 * The error text to display when the alphanumeric validation function returns false
8987 'alphanumText' : 'This field should only contain letters, numbers and _',
8989 * The keystroke filter mask to be applied on alphanumeric input
8992 'alphanumMask' : /[a-z0-9_]/i
9002 * @class Roo.bootstrap.Input
9003 * @extends Roo.bootstrap.Component
9004 * Bootstrap Input class
9005 * @cfg {Boolean} disabled is it disabled
9006 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9007 * @cfg {String} name name of the input
9008 * @cfg {string} fieldLabel - the label associated
9009 * @cfg {string} placeholder - placeholder to put in text.
9010 * @cfg {string} before - input group add on before
9011 * @cfg {string} after - input group add on after
9012 * @cfg {string} size - (lg|sm) or leave empty..
9013 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9014 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9015 * @cfg {Number} md colspan out of 12 for computer-sized screens
9016 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9017 * @cfg {string} value default value of the input
9018 * @cfg {Number} labelWidth set the width of label
9019 * @cfg {Number} labellg set the width of label (1-12)
9020 * @cfg {Number} labelmd set the width of label (1-12)
9021 * @cfg {Number} labelsm set the width of label (1-12)
9022 * @cfg {Number} labelxs set the width of label (1-12)
9023 * @cfg {String} labelAlign (top|left)
9024 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9025 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9026 * @cfg {String} indicatorpos (left|right) default left
9027 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9028 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9030 * @cfg {String} align (left|center|right) Default left
9031 * @cfg {Boolean} forceFeedback (true|false) Default false
9034 * Create a new Input
9035 * @param {Object} config The config object
9038 Roo.bootstrap.Input = function(config){
9040 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9045 * Fires when this field receives input focus.
9046 * @param {Roo.form.Field} this
9051 * Fires when this field loses input focus.
9052 * @param {Roo.form.Field} this
9057 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9058 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9059 * @param {Roo.form.Field} this
9060 * @param {Roo.EventObject} e The event object
9065 * Fires just before the field blurs if the field value has changed.
9066 * @param {Roo.form.Field} this
9067 * @param {Mixed} newValue The new value
9068 * @param {Mixed} oldValue The original value
9073 * Fires after the field has been marked as invalid.
9074 * @param {Roo.form.Field} this
9075 * @param {String} msg The validation message
9080 * Fires after the field has been validated with no errors.
9081 * @param {Roo.form.Field} this
9086 * Fires after the key up
9087 * @param {Roo.form.Field} this
9088 * @param {Roo.EventObject} e The event Object
9094 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9096 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9097 automatic validation (defaults to "keyup").
9099 validationEvent : "keyup",
9101 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9103 validateOnBlur : true,
9105 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9107 validationDelay : 250,
9109 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9111 focusClass : "x-form-focus", // not needed???
9115 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9117 invalidClass : "has-warning",
9120 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9122 validClass : "has-success",
9125 * @cfg {Boolean} hasFeedback (true|false) default true
9130 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9132 invalidFeedbackClass : "glyphicon-warning-sign",
9135 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9137 validFeedbackClass : "glyphicon-ok",
9140 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9142 selectOnFocus : false,
9145 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9149 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9154 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9156 disableKeyFilter : false,
9159 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9163 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9167 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9169 blankText : "Please complete this mandatory field",
9172 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9176 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9178 maxLength : Number.MAX_VALUE,
9180 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9182 minLengthText : "The minimum length for this field is {0}",
9184 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9186 maxLengthText : "The maximum length for this field is {0}",
9190 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9191 * If available, this function will be called only after the basic validators all return true, and will be passed the
9192 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9196 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9197 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9198 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9202 * @cfg {String} regexText -- Depricated - use Invalid Text
9207 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9213 autocomplete: false,
9232 formatedValue : false,
9233 forceFeedback : false,
9235 indicatorpos : 'left',
9245 parentLabelAlign : function()
9248 while (parent.parent()) {
9249 parent = parent.parent();
9250 if (typeof(parent.labelAlign) !='undefined') {
9251 return parent.labelAlign;
9258 getAutoCreate : function()
9260 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9266 if(this.inputType != 'hidden'){
9267 cfg.cls = 'form-group' //input-group
9273 type : this.inputType,
9275 cls : 'form-control',
9276 placeholder : this.placeholder || '',
9277 autocomplete : this.autocomplete || 'new-password'
9280 if(this.capture.length){
9281 input.capture = this.capture;
9284 if(this.accept.length){
9285 input.accept = this.accept + "/*";
9289 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9292 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9293 input.maxLength = this.maxLength;
9296 if (this.disabled) {
9297 input.disabled=true;
9300 if (this.readOnly) {
9301 input.readonly=true;
9305 input.name = this.name;
9309 input.cls += ' input-' + this.size;
9313 ['xs','sm','md','lg'].map(function(size){
9314 if (settings[size]) {
9315 cfg.cls += ' col-' + size + '-' + settings[size];
9319 var inputblock = input;
9323 cls: 'glyphicon form-control-feedback'
9326 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9329 cls : 'has-feedback',
9337 if (this.before || this.after) {
9340 cls : 'input-group',
9344 if (this.before && typeof(this.before) == 'string') {
9346 inputblock.cn.push({
9348 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9352 if (this.before && typeof(this.before) == 'object') {
9353 this.before = Roo.factory(this.before);
9355 inputblock.cn.push({
9357 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9358 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9362 inputblock.cn.push(input);
9364 if (this.after && typeof(this.after) == 'string') {
9365 inputblock.cn.push({
9367 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9371 if (this.after && typeof(this.after) == 'object') {
9372 this.after = Roo.factory(this.after);
9374 inputblock.cn.push({
9376 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9377 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9381 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9382 inputblock.cls += ' has-feedback';
9383 inputblock.cn.push(feedback);
9388 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9389 tooltip : 'This field is required'
9391 if (Roo.bootstrap.version == 4) {
9394 style : 'display-none'
9397 if (align ==='left' && this.fieldLabel.length) {
9399 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9406 cls : 'control-label col-form-label',
9407 html : this.fieldLabel
9418 var labelCfg = cfg.cn[1];
9419 var contentCfg = cfg.cn[2];
9421 if(this.indicatorpos == 'right'){
9426 cls : 'control-label col-form-label',
9430 html : this.fieldLabel
9444 labelCfg = cfg.cn[0];
9445 contentCfg = cfg.cn[1];
9449 if(this.labelWidth > 12){
9450 labelCfg.style = "width: " + this.labelWidth + 'px';
9453 if(this.labelWidth < 13 && this.labelmd == 0){
9454 this.labelmd = this.labelWidth;
9457 if(this.labellg > 0){
9458 labelCfg.cls += ' col-lg-' + this.labellg;
9459 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9462 if(this.labelmd > 0){
9463 labelCfg.cls += ' col-md-' + this.labelmd;
9464 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9467 if(this.labelsm > 0){
9468 labelCfg.cls += ' col-sm-' + this.labelsm;
9469 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9472 if(this.labelxs > 0){
9473 labelCfg.cls += ' col-xs-' + this.labelxs;
9474 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9478 } else if ( this.fieldLabel.length) {
9483 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9484 tooltip : 'This field is required'
9488 //cls : 'input-group-addon',
9489 html : this.fieldLabel
9497 if(this.indicatorpos == 'right'){
9502 //cls : 'input-group-addon',
9503 html : this.fieldLabel
9508 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9509 tooltip : 'This field is required'
9529 if (this.parentType === 'Navbar' && this.parent().bar) {
9530 cfg.cls += ' navbar-form';
9533 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9534 // on BS4 we do this only if not form
9535 cfg.cls += ' navbar-form';
9543 * return the real input element.
9545 inputEl: function ()
9547 return this.el.select('input.form-control',true).first();
9550 tooltipEl : function()
9552 return this.inputEl();
9555 indicatorEl : function()
9557 if (Roo.bootstrap.version == 4) {
9558 return false; // not enabled in v4 yet.
9561 var indicator = this.el.select('i.roo-required-indicator',true).first();
9571 setDisabled : function(v)
9573 var i = this.inputEl().dom;
9575 i.removeAttribute('disabled');
9579 i.setAttribute('disabled','true');
9581 initEvents : function()
9584 this.inputEl().on("keydown" , this.fireKey, this);
9585 this.inputEl().on("focus", this.onFocus, this);
9586 this.inputEl().on("blur", this.onBlur, this);
9588 this.inputEl().relayEvent('keyup', this);
9590 this.indicator = this.indicatorEl();
9593 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9596 // reference to original value for reset
9597 this.originalValue = this.getValue();
9598 //Roo.form.TextField.superclass.initEvents.call(this);
9599 if(this.validationEvent == 'keyup'){
9600 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9601 this.inputEl().on('keyup', this.filterValidation, this);
9603 else if(this.validationEvent !== false){
9604 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9607 if(this.selectOnFocus){
9608 this.on("focus", this.preFocus, this);
9611 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9612 this.inputEl().on("keypress", this.filterKeys, this);
9614 this.inputEl().relayEvent('keypress', this);
9617 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9618 this.el.on("click", this.autoSize, this);
9621 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9622 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9625 if (typeof(this.before) == 'object') {
9626 this.before.render(this.el.select('.roo-input-before',true).first());
9628 if (typeof(this.after) == 'object') {
9629 this.after.render(this.el.select('.roo-input-after',true).first());
9632 this.inputEl().on('change', this.onChange, this);
9635 filterValidation : function(e){
9636 if(!e.isNavKeyPress()){
9637 this.validationTask.delay(this.validationDelay);
9641 * Validates the field value
9642 * @return {Boolean} True if the value is valid, else false
9644 validate : function(){
9645 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9646 if(this.disabled || this.validateValue(this.getRawValue())){
9657 * Validates a value according to the field's validation rules and marks the field as invalid
9658 * if the validation fails
9659 * @param {Mixed} value The value to validate
9660 * @return {Boolean} True if the value is valid, else false
9662 validateValue : function(value)
9664 if(this.getVisibilityEl().hasClass('hidden')){
9668 if(value.length < 1) { // if it's blank
9669 if(this.allowBlank){
9675 if(value.length < this.minLength){
9678 if(value.length > this.maxLength){
9682 var vt = Roo.form.VTypes;
9683 if(!vt[this.vtype](value, this)){
9687 if(typeof this.validator == "function"){
9688 var msg = this.validator(value);
9692 if (typeof(msg) == 'string') {
9693 this.invalidText = msg;
9697 if(this.regex && !this.regex.test(value)){
9705 fireKey : function(e){
9706 //Roo.log('field ' + e.getKey());
9707 if(e.isNavKeyPress()){
9708 this.fireEvent("specialkey", this, e);
9711 focus : function (selectText){
9713 this.inputEl().focus();
9714 if(selectText === true){
9715 this.inputEl().dom.select();
9721 onFocus : function(){
9722 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9723 // this.el.addClass(this.focusClass);
9726 this.hasFocus = true;
9727 this.startValue = this.getValue();
9728 this.fireEvent("focus", this);
9732 beforeBlur : Roo.emptyFn,
9736 onBlur : function(){
9738 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9739 //this.el.removeClass(this.focusClass);
9741 this.hasFocus = false;
9742 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9745 var v = this.getValue();
9746 if(String(v) !== String(this.startValue)){
9747 this.fireEvent('change', this, v, this.startValue);
9749 this.fireEvent("blur", this);
9752 onChange : function(e)
9754 var v = this.getValue();
9755 if(String(v) !== String(this.startValue)){
9756 this.fireEvent('change', this, v, this.startValue);
9762 * Resets the current field value to the originally loaded value and clears any validation messages
9765 this.setValue(this.originalValue);
9769 * Returns the name of the field
9770 * @return {Mixed} name The name field
9772 getName: function(){
9776 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9777 * @return {Mixed} value The field value
9779 getValue : function(){
9781 var v = this.inputEl().getValue();
9786 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9787 * @return {Mixed} value The field value
9789 getRawValue : function(){
9790 var v = this.inputEl().getValue();
9796 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9797 * @param {Mixed} value The value to set
9799 setRawValue : function(v){
9800 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9803 selectText : function(start, end){
9804 var v = this.getRawValue();
9806 start = start === undefined ? 0 : start;
9807 end = end === undefined ? v.length : end;
9808 var d = this.inputEl().dom;
9809 if(d.setSelectionRange){
9810 d.setSelectionRange(start, end);
9811 }else if(d.createTextRange){
9812 var range = d.createTextRange();
9813 range.moveStart("character", start);
9814 range.moveEnd("character", v.length-end);
9821 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9822 * @param {Mixed} value The value to set
9824 setValue : function(v){
9827 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9833 processValue : function(value){
9834 if(this.stripCharsRe){
9835 var newValue = value.replace(this.stripCharsRe, '');
9836 if(newValue !== value){
9837 this.setRawValue(newValue);
9844 preFocus : function(){
9846 if(this.selectOnFocus){
9847 this.inputEl().dom.select();
9850 filterKeys : function(e){
9852 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9855 var c = e.getCharCode(), cc = String.fromCharCode(c);
9856 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9859 if(!this.maskRe.test(cc)){
9864 * Clear any invalid styles/messages for this field
9866 clearInvalid : function(){
9868 if(!this.el || this.preventMark){ // not rendered
9873 this.el.removeClass([this.invalidClass, 'is-invalid']);
9875 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9877 var feedback = this.el.select('.form-control-feedback', true).first();
9880 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9886 this.indicator.removeClass('visible');
9887 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9890 this.fireEvent('valid', this);
9894 * Mark this field as valid
9896 markValid : function()
9898 if(!this.el || this.preventMark){ // not rendered...
9902 this.el.removeClass([this.invalidClass, this.validClass]);
9903 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9905 var feedback = this.el.select('.form-control-feedback', true).first();
9908 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9912 this.indicator.removeClass('visible');
9913 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9920 if(this.allowBlank && !this.getRawValue().length){
9923 if (Roo.bootstrap.version == 3) {
9924 this.el.addClass(this.validClass);
9926 this.inputEl().addClass('is-valid');
9929 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9931 var feedback = this.el.select('.form-control-feedback', true).first();
9934 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9935 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9940 this.fireEvent('valid', this);
9944 * Mark this field as invalid
9945 * @param {String} msg The validation message
9947 markInvalid : function(msg)
9949 if(!this.el || this.preventMark){ // not rendered
9953 this.el.removeClass([this.invalidClass, this.validClass]);
9954 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9956 var feedback = this.el.select('.form-control-feedback', true).first();
9959 this.el.select('.form-control-feedback', true).first().removeClass(
9960 [this.invalidFeedbackClass, this.validFeedbackClass]);
9967 if(this.allowBlank && !this.getRawValue().length){
9972 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9973 this.indicator.addClass('visible');
9975 if (Roo.bootstrap.version == 3) {
9976 this.el.addClass(this.invalidClass);
9978 this.inputEl().addClass('is-invalid');
9983 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9985 var feedback = this.el.select('.form-control-feedback', true).first();
9988 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9990 if(this.getValue().length || this.forceFeedback){
9991 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9998 this.fireEvent('invalid', this, msg);
10001 SafariOnKeyDown : function(event)
10003 // this is a workaround for a password hang bug on chrome/ webkit.
10004 if (this.inputEl().dom.type != 'password') {
10008 var isSelectAll = false;
10010 if(this.inputEl().dom.selectionEnd > 0){
10011 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10013 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10014 event.preventDefault();
10019 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10021 event.preventDefault();
10022 // this is very hacky as keydown always get's upper case.
10024 var cc = String.fromCharCode(event.getCharCode());
10025 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10029 adjustWidth : function(tag, w){
10030 tag = tag.toLowerCase();
10031 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10032 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10033 if(tag == 'input'){
10036 if(tag == 'textarea'){
10039 }else if(Roo.isOpera){
10040 if(tag == 'input'){
10043 if(tag == 'textarea'){
10051 setFieldLabel : function(v)
10053 if(!this.rendered){
10057 if(this.indicatorEl()){
10058 var ar = this.el.select('label > span',true);
10060 if (ar.elements.length) {
10061 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10062 this.fieldLabel = v;
10066 var br = this.el.select('label',true);
10068 if(br.elements.length) {
10069 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10070 this.fieldLabel = v;
10074 Roo.log('Cannot Found any of label > span || label in input');
10078 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10079 this.fieldLabel = v;
10094 * @class Roo.bootstrap.TextArea
10095 * @extends Roo.bootstrap.Input
10096 * Bootstrap TextArea class
10097 * @cfg {Number} cols Specifies the visible width of a text area
10098 * @cfg {Number} rows Specifies the visible number of lines in a text area
10099 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10100 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10101 * @cfg {string} html text
10104 * Create a new TextArea
10105 * @param {Object} config The config object
10108 Roo.bootstrap.TextArea = function(config){
10109 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10113 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10123 getAutoCreate : function(){
10125 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10131 if(this.inputType != 'hidden'){
10132 cfg.cls = 'form-group' //input-group
10140 value : this.value || '',
10141 html: this.html || '',
10142 cls : 'form-control',
10143 placeholder : this.placeholder || ''
10147 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10148 input.maxLength = this.maxLength;
10152 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10156 input.cols = this.cols;
10159 if (this.readOnly) {
10160 input.readonly = true;
10164 input.name = this.name;
10168 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10172 ['xs','sm','md','lg'].map(function(size){
10173 if (settings[size]) {
10174 cfg.cls += ' col-' + size + '-' + settings[size];
10178 var inputblock = input;
10180 if(this.hasFeedback && !this.allowBlank){
10184 cls: 'glyphicon form-control-feedback'
10188 cls : 'has-feedback',
10197 if (this.before || this.after) {
10200 cls : 'input-group',
10204 inputblock.cn.push({
10206 cls : 'input-group-addon',
10211 inputblock.cn.push(input);
10213 if(this.hasFeedback && !this.allowBlank){
10214 inputblock.cls += ' has-feedback';
10215 inputblock.cn.push(feedback);
10219 inputblock.cn.push({
10221 cls : 'input-group-addon',
10228 if (align ==='left' && this.fieldLabel.length) {
10233 cls : 'control-label',
10234 html : this.fieldLabel
10245 if(this.labelWidth > 12){
10246 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10249 if(this.labelWidth < 13 && this.labelmd == 0){
10250 this.labelmd = this.labelWidth;
10253 if(this.labellg > 0){
10254 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10255 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10258 if(this.labelmd > 0){
10259 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10260 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10263 if(this.labelsm > 0){
10264 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10265 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10268 if(this.labelxs > 0){
10269 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10270 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10273 } else if ( this.fieldLabel.length) {
10278 //cls : 'input-group-addon',
10279 html : this.fieldLabel
10297 if (this.disabled) {
10298 input.disabled=true;
10305 * return the real textarea element.
10307 inputEl: function ()
10309 return this.el.select('textarea.form-control',true).first();
10313 * Clear any invalid styles/messages for this field
10315 clearInvalid : function()
10318 if(!this.el || this.preventMark){ // not rendered
10322 var label = this.el.select('label', true).first();
10323 var icon = this.el.select('i.fa-star', true).first();
10328 this.el.removeClass( this.validClass);
10329 this.inputEl().removeClass('is-invalid');
10331 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10333 var feedback = this.el.select('.form-control-feedback', true).first();
10336 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10341 this.fireEvent('valid', this);
10345 * Mark this field as valid
10347 markValid : function()
10349 if(!this.el || this.preventMark){ // not rendered
10353 this.el.removeClass([this.invalidClass, this.validClass]);
10354 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10356 var feedback = this.el.select('.form-control-feedback', true).first();
10359 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10362 if(this.disabled || this.allowBlank){
10366 var label = this.el.select('label', true).first();
10367 var icon = this.el.select('i.fa-star', true).first();
10372 if (Roo.bootstrap.version == 3) {
10373 this.el.addClass(this.validClass);
10375 this.inputEl().addClass('is-valid');
10379 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10381 var feedback = this.el.select('.form-control-feedback', true).first();
10384 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10385 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10390 this.fireEvent('valid', this);
10394 * Mark this field as invalid
10395 * @param {String} msg The validation message
10397 markInvalid : function(msg)
10399 if(!this.el || this.preventMark){ // not rendered
10403 this.el.removeClass([this.invalidClass, this.validClass]);
10404 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10406 var feedback = this.el.select('.form-control-feedback', true).first();
10409 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10412 if(this.disabled || this.allowBlank){
10416 var label = this.el.select('label', true).first();
10417 var icon = this.el.select('i.fa-star', true).first();
10419 if(!this.getValue().length && label && !icon){
10420 this.el.createChild({
10422 cls : 'text-danger fa fa-lg fa-star',
10423 tooltip : 'This field is required',
10424 style : 'margin-right:5px;'
10428 if (Roo.bootstrap.version == 3) {
10429 this.el.addClass(this.invalidClass);
10431 this.inputEl().addClass('is-invalid');
10434 // fixme ... this may be depricated need to test..
10435 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10437 var feedback = this.el.select('.form-control-feedback', true).first();
10440 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10442 if(this.getValue().length || this.forceFeedback){
10443 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10450 this.fireEvent('invalid', this, msg);
10458 * trigger field - base class for combo..
10463 * @class Roo.bootstrap.TriggerField
10464 * @extends Roo.bootstrap.Input
10465 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10466 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10467 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10468 * for which you can provide a custom implementation. For example:
10470 var trigger = new Roo.bootstrap.TriggerField();
10471 trigger.onTriggerClick = myTriggerFn;
10472 trigger.applyTo('my-field');
10475 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10476 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10477 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10478 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10479 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
10482 * Create a new TriggerField.
10483 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10484 * to the base TextField)
10486 Roo.bootstrap.TriggerField = function(config){
10487 this.mimicing = false;
10488 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10491 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10493 * @cfg {String} triggerClass A CSS class to apply to the trigger
10496 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10501 * @cfg {Boolean} removable (true|false) special filter default false
10505 /** @cfg {Boolean} grow @hide */
10506 /** @cfg {Number} growMin @hide */
10507 /** @cfg {Number} growMax @hide */
10513 autoSize: Roo.emptyFn,
10517 deferHeight : true,
10520 actionMode : 'wrap',
10525 getAutoCreate : function(){
10527 var align = this.labelAlign || this.parentLabelAlign();
10532 cls: 'form-group' //input-group
10539 type : this.inputType,
10540 cls : 'form-control',
10541 autocomplete: 'new-password',
10542 placeholder : this.placeholder || ''
10546 input.name = this.name;
10549 input.cls += ' input-' + this.size;
10552 if (this.disabled) {
10553 input.disabled=true;
10556 var inputblock = input;
10558 if(this.hasFeedback && !this.allowBlank){
10562 cls: 'glyphicon form-control-feedback'
10565 if(this.removable && !this.editable && !this.tickable){
10567 cls : 'has-feedback',
10573 cls : 'roo-combo-removable-btn close'
10580 cls : 'has-feedback',
10589 if(this.removable && !this.editable && !this.tickable){
10591 cls : 'roo-removable',
10597 cls : 'roo-combo-removable-btn close'
10604 if (this.before || this.after) {
10607 cls : 'input-group',
10611 inputblock.cn.push({
10613 cls : 'input-group-addon input-group-prepend input-group-text',
10618 inputblock.cn.push(input);
10620 if(this.hasFeedback && !this.allowBlank){
10621 inputblock.cls += ' has-feedback';
10622 inputblock.cn.push(feedback);
10626 inputblock.cn.push({
10628 cls : 'input-group-addon input-group-append input-group-text',
10637 var ibwrap = inputblock;
10642 cls: 'roo-select2-choices',
10646 cls: 'roo-select2-search-field',
10658 cls: 'roo-select2-container input-group',
10663 cls: 'form-hidden-field'
10669 if(!this.multiple && this.showToggleBtn){
10675 if (this.caret != false) {
10678 cls: 'fa fa-' + this.caret
10685 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10687 Roo.bootstrap.version == 3 ? caret : '',
10690 cls: 'combobox-clear',
10704 combobox.cls += ' roo-select2-container-multi';
10708 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10709 tooltip : 'This field is required'
10711 if (Roo.bootstrap.version == 4) {
10714 style : 'display:none'
10719 if (align ==='left' && this.fieldLabel.length) {
10721 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10728 cls : 'control-label',
10729 html : this.fieldLabel
10741 var labelCfg = cfg.cn[1];
10742 var contentCfg = cfg.cn[2];
10744 if(this.indicatorpos == 'right'){
10749 cls : 'control-label',
10753 html : this.fieldLabel
10767 labelCfg = cfg.cn[0];
10768 contentCfg = cfg.cn[1];
10771 if(this.labelWidth > 12){
10772 labelCfg.style = "width: " + this.labelWidth + 'px';
10775 if(this.labelWidth < 13 && this.labelmd == 0){
10776 this.labelmd = this.labelWidth;
10779 if(this.labellg > 0){
10780 labelCfg.cls += ' col-lg-' + this.labellg;
10781 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10784 if(this.labelmd > 0){
10785 labelCfg.cls += ' col-md-' + this.labelmd;
10786 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10789 if(this.labelsm > 0){
10790 labelCfg.cls += ' col-sm-' + this.labelsm;
10791 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10794 if(this.labelxs > 0){
10795 labelCfg.cls += ' col-xs-' + this.labelxs;
10796 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10799 } else if ( this.fieldLabel.length) {
10800 // Roo.log(" label");
10805 //cls : 'input-group-addon',
10806 html : this.fieldLabel
10814 if(this.indicatorpos == 'right'){
10822 html : this.fieldLabel
10836 // Roo.log(" no label && no align");
10843 ['xs','sm','md','lg'].map(function(size){
10844 if (settings[size]) {
10845 cfg.cls += ' col-' + size + '-' + settings[size];
10856 onResize : function(w, h){
10857 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10858 // if(typeof w == 'number'){
10859 // var x = w - this.trigger.getWidth();
10860 // this.inputEl().setWidth(this.adjustWidth('input', x));
10861 // this.trigger.setStyle('left', x+'px');
10866 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10869 getResizeEl : function(){
10870 return this.inputEl();
10874 getPositionEl : function(){
10875 return this.inputEl();
10879 alignErrorIcon : function(){
10880 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10884 initEvents : function(){
10888 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10889 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10890 if(!this.multiple && this.showToggleBtn){
10891 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10892 if(this.hideTrigger){
10893 this.trigger.setDisplayed(false);
10895 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10899 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10902 if(this.removable && !this.editable && !this.tickable){
10903 var close = this.closeTriggerEl();
10906 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10907 close.on('click', this.removeBtnClick, this, close);
10911 //this.trigger.addClassOnOver('x-form-trigger-over');
10912 //this.trigger.addClassOnClick('x-form-trigger-click');
10915 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10919 closeTriggerEl : function()
10921 var close = this.el.select('.roo-combo-removable-btn', true).first();
10922 return close ? close : false;
10925 removeBtnClick : function(e, h, el)
10927 e.preventDefault();
10929 if(this.fireEvent("remove", this) !== false){
10931 this.fireEvent("afterremove", this)
10935 createList : function()
10937 this.list = Roo.get(document.body).createChild({
10938 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10939 cls: 'typeahead typeahead-long dropdown-menu',
10940 style: 'display:none'
10943 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10948 initTrigger : function(){
10953 onDestroy : function(){
10955 this.trigger.removeAllListeners();
10956 // this.trigger.remove();
10959 // this.wrap.remove();
10961 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10965 onFocus : function(){
10966 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10968 if(!this.mimicing){
10969 this.wrap.addClass('x-trigger-wrap-focus');
10970 this.mimicing = true;
10971 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10972 if(this.monitorTab){
10973 this.el.on("keydown", this.checkTab, this);
10980 checkTab : function(e){
10981 if(e.getKey() == e.TAB){
10982 this.triggerBlur();
10987 onBlur : function(){
10992 mimicBlur : function(e, t){
10994 if(!this.wrap.contains(t) && this.validateBlur()){
10995 this.triggerBlur();
11001 triggerBlur : function(){
11002 this.mimicing = false;
11003 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
11004 if(this.monitorTab){
11005 this.el.un("keydown", this.checkTab, this);
11007 //this.wrap.removeClass('x-trigger-wrap-focus');
11008 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11012 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11013 validateBlur : function(e, t){
11018 onDisable : function(){
11019 this.inputEl().dom.disabled = true;
11020 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11022 // this.wrap.addClass('x-item-disabled');
11027 onEnable : function(){
11028 this.inputEl().dom.disabled = false;
11029 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11031 // this.el.removeClass('x-item-disabled');
11036 onShow : function(){
11037 var ae = this.getActionEl();
11040 ae.dom.style.display = '';
11041 ae.dom.style.visibility = 'visible';
11047 onHide : function(){
11048 var ae = this.getActionEl();
11049 ae.dom.style.display = 'none';
11053 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11054 * by an implementing function.
11056 * @param {EventObject} e
11058 onTriggerClick : Roo.emptyFn
11062 * Ext JS Library 1.1.1
11063 * Copyright(c) 2006-2007, Ext JS, LLC.
11065 * Originally Released Under LGPL - original licence link has changed is not relivant.
11068 * <script type="text/javascript">
11073 * @class Roo.data.SortTypes
11075 * Defines the default sorting (casting?) comparison functions used when sorting data.
11077 Roo.data.SortTypes = {
11079 * Default sort that does nothing
11080 * @param {Mixed} s The value being converted
11081 * @return {Mixed} The comparison value
11083 none : function(s){
11088 * The regular expression used to strip tags
11092 stripTagsRE : /<\/?[^>]+>/gi,
11095 * Strips all HTML tags to sort on text only
11096 * @param {Mixed} s The value being converted
11097 * @return {String} The comparison value
11099 asText : function(s){
11100 return String(s).replace(this.stripTagsRE, "");
11104 * Strips all HTML tags to sort on text only - Case insensitive
11105 * @param {Mixed} s The value being converted
11106 * @return {String} The comparison value
11108 asUCText : function(s){
11109 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11113 * Case insensitive string
11114 * @param {Mixed} s The value being converted
11115 * @return {String} The comparison value
11117 asUCString : function(s) {
11118 return String(s).toUpperCase();
11123 * @param {Mixed} s The value being converted
11124 * @return {Number} The comparison value
11126 asDate : function(s) {
11130 if(s instanceof Date){
11131 return s.getTime();
11133 return Date.parse(String(s));
11138 * @param {Mixed} s The value being converted
11139 * @return {Float} The comparison value
11141 asFloat : function(s) {
11142 var val = parseFloat(String(s).replace(/,/g, ""));
11151 * @param {Mixed} s The value being converted
11152 * @return {Number} The comparison value
11154 asInt : function(s) {
11155 var val = parseInt(String(s).replace(/,/g, ""));
11163 * Ext JS Library 1.1.1
11164 * Copyright(c) 2006-2007, Ext JS, LLC.
11166 * Originally Released Under LGPL - original licence link has changed is not relivant.
11169 * <script type="text/javascript">
11173 * @class Roo.data.Record
11174 * Instances of this class encapsulate both record <em>definition</em> information, and record
11175 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11176 * to access Records cached in an {@link Roo.data.Store} object.<br>
11178 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11179 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11182 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11184 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11185 * {@link #create}. The parameters are the same.
11186 * @param {Array} data An associative Array of data values keyed by the field name.
11187 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11188 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11189 * not specified an integer id is generated.
11191 Roo.data.Record = function(data, id){
11192 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11197 * Generate a constructor for a specific record layout.
11198 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11199 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11200 * Each field definition object may contain the following properties: <ul>
11201 * <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,
11202 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11203 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11204 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11205 * is being used, then this is a string containing the javascript expression to reference the data relative to
11206 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11207 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11208 * this may be omitted.</p></li>
11209 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11210 * <ul><li>auto (Default, implies no conversion)</li>
11215 * <li>date</li></ul></p></li>
11216 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11217 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11218 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11219 * by the Reader into an object that will be stored in the Record. It is passed the
11220 * following parameters:<ul>
11221 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11223 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11225 * <br>usage:<br><pre><code>
11226 var TopicRecord = Roo.data.Record.create(
11227 {name: 'title', mapping: 'topic_title'},
11228 {name: 'author', mapping: 'username'},
11229 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11230 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11231 {name: 'lastPoster', mapping: 'user2'},
11232 {name: 'excerpt', mapping: 'post_text'}
11235 var myNewRecord = new TopicRecord({
11236 title: 'Do my job please',
11239 lastPost: new Date(),
11240 lastPoster: 'Animal',
11241 excerpt: 'No way dude!'
11243 myStore.add(myNewRecord);
11248 Roo.data.Record.create = function(o){
11249 var f = function(){
11250 f.superclass.constructor.apply(this, arguments);
11252 Roo.extend(f, Roo.data.Record);
11253 var p = f.prototype;
11254 p.fields = new Roo.util.MixedCollection(false, function(field){
11257 for(var i = 0, len = o.length; i < len; i++){
11258 p.fields.add(new Roo.data.Field(o[i]));
11260 f.getField = function(name){
11261 return p.fields.get(name);
11266 Roo.data.Record.AUTO_ID = 1000;
11267 Roo.data.Record.EDIT = 'edit';
11268 Roo.data.Record.REJECT = 'reject';
11269 Roo.data.Record.COMMIT = 'commit';
11271 Roo.data.Record.prototype = {
11273 * Readonly flag - true if this record has been modified.
11282 join : function(store){
11283 this.store = store;
11287 * Set the named field to the specified value.
11288 * @param {String} name The name of the field to set.
11289 * @param {Object} value The value to set the field to.
11291 set : function(name, value){
11292 if(this.data[name] == value){
11296 if(!this.modified){
11297 this.modified = {};
11299 if(typeof this.modified[name] == 'undefined'){
11300 this.modified[name] = this.data[name];
11302 this.data[name] = value;
11303 if(!this.editing && this.store){
11304 this.store.afterEdit(this);
11309 * Get the value of the named field.
11310 * @param {String} name The name of the field to get the value of.
11311 * @return {Object} The value of the field.
11313 get : function(name){
11314 return this.data[name];
11318 beginEdit : function(){
11319 this.editing = true;
11320 this.modified = {};
11324 cancelEdit : function(){
11325 this.editing = false;
11326 delete this.modified;
11330 endEdit : function(){
11331 this.editing = false;
11332 if(this.dirty && this.store){
11333 this.store.afterEdit(this);
11338 * Usually called by the {@link Roo.data.Store} which owns the Record.
11339 * Rejects all changes made to the Record since either creation, or the last commit operation.
11340 * Modified fields are reverted to their original values.
11342 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11343 * of reject operations.
11345 reject : function(){
11346 var m = this.modified;
11348 if(typeof m[n] != "function"){
11349 this.data[n] = m[n];
11352 this.dirty = false;
11353 delete this.modified;
11354 this.editing = false;
11356 this.store.afterReject(this);
11361 * Usually called by the {@link Roo.data.Store} which owns the Record.
11362 * Commits all changes made to the Record since either creation, or the last commit operation.
11364 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11365 * of commit operations.
11367 commit : function(){
11368 this.dirty = false;
11369 delete this.modified;
11370 this.editing = false;
11372 this.store.afterCommit(this);
11377 hasError : function(){
11378 return this.error != null;
11382 clearError : function(){
11387 * Creates a copy of this record.
11388 * @param {String} id (optional) A new record id if you don't want to use this record's id
11391 copy : function(newId) {
11392 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11396 * Ext JS Library 1.1.1
11397 * Copyright(c) 2006-2007, Ext JS, LLC.
11399 * Originally Released Under LGPL - original licence link has changed is not relivant.
11402 * <script type="text/javascript">
11408 * @class Roo.data.Store
11409 * @extends Roo.util.Observable
11410 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11411 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11413 * 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
11414 * has no knowledge of the format of the data returned by the Proxy.<br>
11416 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11417 * instances from the data object. These records are cached and made available through accessor functions.
11419 * Creates a new Store.
11420 * @param {Object} config A config object containing the objects needed for the Store to access data,
11421 * and read the data into Records.
11423 Roo.data.Store = function(config){
11424 this.data = new Roo.util.MixedCollection(false);
11425 this.data.getKey = function(o){
11428 this.baseParams = {};
11430 this.paramNames = {
11435 "multisort" : "_multisort"
11438 if(config && config.data){
11439 this.inlineData = config.data;
11440 delete config.data;
11443 Roo.apply(this, config);
11445 if(this.reader){ // reader passed
11446 this.reader = Roo.factory(this.reader, Roo.data);
11447 this.reader.xmodule = this.xmodule || false;
11448 if(!this.recordType){
11449 this.recordType = this.reader.recordType;
11451 if(this.reader.onMetaChange){
11452 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11456 if(this.recordType){
11457 this.fields = this.recordType.prototype.fields;
11459 this.modified = [];
11463 * @event datachanged
11464 * Fires when the data cache has changed, and a widget which is using this Store
11465 * as a Record cache should refresh its view.
11466 * @param {Store} this
11468 datachanged : true,
11470 * @event metachange
11471 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11472 * @param {Store} this
11473 * @param {Object} meta The JSON metadata
11478 * Fires when Records have been added to the Store
11479 * @param {Store} this
11480 * @param {Roo.data.Record[]} records The array of Records added
11481 * @param {Number} index The index at which the record(s) were added
11486 * Fires when a Record has been removed from the Store
11487 * @param {Store} this
11488 * @param {Roo.data.Record} record The Record that was removed
11489 * @param {Number} index The index at which the record was removed
11494 * Fires when a Record has been updated
11495 * @param {Store} this
11496 * @param {Roo.data.Record} record The Record that was updated
11497 * @param {String} operation The update operation being performed. Value may be one of:
11499 Roo.data.Record.EDIT
11500 Roo.data.Record.REJECT
11501 Roo.data.Record.COMMIT
11507 * Fires when the data cache has been cleared.
11508 * @param {Store} this
11512 * @event beforeload
11513 * Fires before a request is made for a new data object. If the beforeload handler returns false
11514 * the load action will be canceled.
11515 * @param {Store} this
11516 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11520 * @event beforeloadadd
11521 * Fires after a new set of Records has been loaded.
11522 * @param {Store} this
11523 * @param {Roo.data.Record[]} records The Records that were loaded
11524 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11526 beforeloadadd : true,
11529 * Fires after a new set of Records has been loaded, before they are added to the store.
11530 * @param {Store} this
11531 * @param {Roo.data.Record[]} records The Records that were loaded
11532 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11533 * @params {Object} return from reader
11537 * @event loadexception
11538 * Fires if an exception occurs in the Proxy during loading.
11539 * Called with the signature of the Proxy's "loadexception" event.
11540 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11543 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11544 * @param {Object} load options
11545 * @param {Object} jsonData from your request (normally this contains the Exception)
11547 loadexception : true
11551 this.proxy = Roo.factory(this.proxy, Roo.data);
11552 this.proxy.xmodule = this.xmodule || false;
11553 this.relayEvents(this.proxy, ["loadexception"]);
11555 this.sortToggle = {};
11556 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11558 Roo.data.Store.superclass.constructor.call(this);
11560 if(this.inlineData){
11561 this.loadData(this.inlineData);
11562 delete this.inlineData;
11566 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11568 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11569 * without a remote query - used by combo/forms at present.
11573 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11576 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11579 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11580 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11583 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11584 * on any HTTP request
11587 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11590 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11594 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11595 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11597 remoteSort : false,
11600 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11601 * loaded or when a record is removed. (defaults to false).
11603 pruneModifiedRecords : false,
11606 lastOptions : null,
11609 * Add Records to the Store and fires the add event.
11610 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11612 add : function(records){
11613 records = [].concat(records);
11614 for(var i = 0, len = records.length; i < len; i++){
11615 records[i].join(this);
11617 var index = this.data.length;
11618 this.data.addAll(records);
11619 this.fireEvent("add", this, records, index);
11623 * Remove a Record from the Store and fires the remove event.
11624 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11626 remove : function(record){
11627 var index = this.data.indexOf(record);
11628 this.data.removeAt(index);
11630 if(this.pruneModifiedRecords){
11631 this.modified.remove(record);
11633 this.fireEvent("remove", this, record, index);
11637 * Remove all Records from the Store and fires the clear event.
11639 removeAll : function(){
11641 if(this.pruneModifiedRecords){
11642 this.modified = [];
11644 this.fireEvent("clear", this);
11648 * Inserts Records to the Store at the given index and fires the add event.
11649 * @param {Number} index The start index at which to insert the passed Records.
11650 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11652 insert : function(index, records){
11653 records = [].concat(records);
11654 for(var i = 0, len = records.length; i < len; i++){
11655 this.data.insert(index, records[i]);
11656 records[i].join(this);
11658 this.fireEvent("add", this, records, index);
11662 * Get the index within the cache of the passed Record.
11663 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11664 * @return {Number} The index of the passed Record. Returns -1 if not found.
11666 indexOf : function(record){
11667 return this.data.indexOf(record);
11671 * Get the index within the cache of the Record with the passed id.
11672 * @param {String} id The id of the Record to find.
11673 * @return {Number} The index of the Record. Returns -1 if not found.
11675 indexOfId : function(id){
11676 return this.data.indexOfKey(id);
11680 * Get the Record with the specified id.
11681 * @param {String} id The id of the Record to find.
11682 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11684 getById : function(id){
11685 return this.data.key(id);
11689 * Get the Record at the specified index.
11690 * @param {Number} index The index of the Record to find.
11691 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11693 getAt : function(index){
11694 return this.data.itemAt(index);
11698 * Returns a range of Records between specified indices.
11699 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11700 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11701 * @return {Roo.data.Record[]} An array of Records
11703 getRange : function(start, end){
11704 return this.data.getRange(start, end);
11708 storeOptions : function(o){
11709 o = Roo.apply({}, o);
11712 this.lastOptions = o;
11716 * Loads the Record cache from the configured Proxy using the configured Reader.
11718 * If using remote paging, then the first load call must specify the <em>start</em>
11719 * and <em>limit</em> properties in the options.params property to establish the initial
11720 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11722 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11723 * and this call will return before the new data has been loaded. Perform any post-processing
11724 * in a callback function, or in a "load" event handler.</strong>
11726 * @param {Object} options An object containing properties which control loading options:<ul>
11727 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11728 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11729 * passed the following arguments:<ul>
11730 * <li>r : Roo.data.Record[]</li>
11731 * <li>options: Options object from the load call</li>
11732 * <li>success: Boolean success indicator</li></ul></li>
11733 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11734 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11737 load : function(options){
11738 options = options || {};
11739 if(this.fireEvent("beforeload", this, options) !== false){
11740 this.storeOptions(options);
11741 var p = Roo.apply(options.params || {}, this.baseParams);
11742 // if meta was not loaded from remote source.. try requesting it.
11743 if (!this.reader.metaFromRemote) {
11744 p._requestMeta = 1;
11746 if(this.sortInfo && this.remoteSort){
11747 var pn = this.paramNames;
11748 p[pn["sort"]] = this.sortInfo.field;
11749 p[pn["dir"]] = this.sortInfo.direction;
11751 if (this.multiSort) {
11752 var pn = this.paramNames;
11753 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11756 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11761 * Reloads the Record cache from the configured Proxy using the configured Reader and
11762 * the options from the last load operation performed.
11763 * @param {Object} options (optional) An object containing properties which may override the options
11764 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11765 * the most recently used options are reused).
11767 reload : function(options){
11768 this.load(Roo.applyIf(options||{}, this.lastOptions));
11772 // Called as a callback by the Reader during a load operation.
11773 loadRecords : function(o, options, success){
11774 if(!o || success === false){
11775 if(success !== false){
11776 this.fireEvent("load", this, [], options, o);
11778 if(options.callback){
11779 options.callback.call(options.scope || this, [], options, false);
11783 // if data returned failure - throw an exception.
11784 if (o.success === false) {
11785 // show a message if no listener is registered.
11786 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11787 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11789 // loadmask wil be hooked into this..
11790 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11793 var r = o.records, t = o.totalRecords || r.length;
11795 this.fireEvent("beforeloadadd", this, r, options, o);
11797 if(!options || options.add !== true){
11798 if(this.pruneModifiedRecords){
11799 this.modified = [];
11801 for(var i = 0, len = r.length; i < len; i++){
11805 this.data = this.snapshot;
11806 delete this.snapshot;
11809 this.data.addAll(r);
11810 this.totalLength = t;
11812 this.fireEvent("datachanged", this);
11814 this.totalLength = Math.max(t, this.data.length+r.length);
11818 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11820 var e = new Roo.data.Record({});
11822 e.set(this.parent.displayField, this.parent.emptyTitle);
11823 e.set(this.parent.valueField, '');
11828 this.fireEvent("load", this, r, options, o);
11829 if(options.callback){
11830 options.callback.call(options.scope || this, r, options, true);
11836 * Loads data from a passed data block. A Reader which understands the format of the data
11837 * must have been configured in the constructor.
11838 * @param {Object} data The data block from which to read the Records. The format of the data expected
11839 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11840 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11842 loadData : function(o, append){
11843 var r = this.reader.readRecords(o);
11844 this.loadRecords(r, {add: append}, true);
11848 * Gets the number of cached records.
11850 * <em>If using paging, this may not be the total size of the dataset. If the data object
11851 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11852 * the data set size</em>
11854 getCount : function(){
11855 return this.data.length || 0;
11859 * Gets the total number of records in the dataset as returned by the server.
11861 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11862 * the dataset size</em>
11864 getTotalCount : function(){
11865 return this.totalLength || 0;
11869 * Returns the sort state of the Store as an object with two properties:
11871 field {String} The name of the field by which the Records are sorted
11872 direction {String} The sort order, "ASC" or "DESC"
11875 getSortState : function(){
11876 return this.sortInfo;
11880 applySort : function(){
11881 if(this.sortInfo && !this.remoteSort){
11882 var s = this.sortInfo, f = s.field;
11883 var st = this.fields.get(f).sortType;
11884 var fn = function(r1, r2){
11885 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11886 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11888 this.data.sort(s.direction, fn);
11889 if(this.snapshot && this.snapshot != this.data){
11890 this.snapshot.sort(s.direction, fn);
11896 * Sets the default sort column and order to be used by the next load operation.
11897 * @param {String} fieldName The name of the field to sort by.
11898 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11900 setDefaultSort : function(field, dir){
11901 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11905 * Sort the Records.
11906 * If remote sorting is used, the sort is performed on the server, and the cache is
11907 * reloaded. If local sorting is used, the cache is sorted internally.
11908 * @param {String} fieldName The name of the field to sort by.
11909 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11911 sort : function(fieldName, dir){
11912 var f = this.fields.get(fieldName);
11914 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11916 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11917 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11922 this.sortToggle[f.name] = dir;
11923 this.sortInfo = {field: f.name, direction: dir};
11924 if(!this.remoteSort){
11926 this.fireEvent("datachanged", this);
11928 this.load(this.lastOptions);
11933 * Calls the specified function for each of the Records in the cache.
11934 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11935 * Returning <em>false</em> aborts and exits the iteration.
11936 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11938 each : function(fn, scope){
11939 this.data.each(fn, scope);
11943 * Gets all records modified since the last commit. Modified records are persisted across load operations
11944 * (e.g., during paging).
11945 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11947 getModifiedRecords : function(){
11948 return this.modified;
11952 createFilterFn : function(property, value, anyMatch){
11953 if(!value.exec){ // not a regex
11954 value = String(value);
11955 if(value.length == 0){
11958 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11960 return function(r){
11961 return value.test(r.data[property]);
11966 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11967 * @param {String} property A field on your records
11968 * @param {Number} start The record index to start at (defaults to 0)
11969 * @param {Number} end The last record index to include (defaults to length - 1)
11970 * @return {Number} The sum
11972 sum : function(property, start, end){
11973 var rs = this.data.items, v = 0;
11974 start = start || 0;
11975 end = (end || end === 0) ? end : rs.length-1;
11977 for(var i = start; i <= end; i++){
11978 v += (rs[i].data[property] || 0);
11984 * Filter the records by a specified property.
11985 * @param {String} field A field on your records
11986 * @param {String/RegExp} value Either a string that the field
11987 * should start with or a RegExp to test against the field
11988 * @param {Boolean} anyMatch True to match any part not just the beginning
11990 filter : function(property, value, anyMatch){
11991 var fn = this.createFilterFn(property, value, anyMatch);
11992 return fn ? this.filterBy(fn) : this.clearFilter();
11996 * Filter by a function. The specified function will be called with each
11997 * record in this data source. If the function returns true the record is included,
11998 * otherwise it is filtered.
11999 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12000 * @param {Object} scope (optional) The scope of the function (defaults to this)
12002 filterBy : function(fn, scope){
12003 this.snapshot = this.snapshot || this.data;
12004 this.data = this.queryBy(fn, scope||this);
12005 this.fireEvent("datachanged", this);
12009 * Query the records by a specified property.
12010 * @param {String} field A field on your records
12011 * @param {String/RegExp} value Either a string that the field
12012 * should start with or a RegExp to test against the field
12013 * @param {Boolean} anyMatch True to match any part not just the beginning
12014 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12016 query : function(property, value, anyMatch){
12017 var fn = this.createFilterFn(property, value, anyMatch);
12018 return fn ? this.queryBy(fn) : this.data.clone();
12022 * Query by a function. The specified function will be called with each
12023 * record in this data source. If the function returns true the record is included
12025 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12026 * @param {Object} scope (optional) The scope of the function (defaults to this)
12027 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12029 queryBy : function(fn, scope){
12030 var data = this.snapshot || this.data;
12031 return data.filterBy(fn, scope||this);
12035 * Collects unique values for a particular dataIndex from this store.
12036 * @param {String} dataIndex The property to collect
12037 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12038 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12039 * @return {Array} An array of the unique values
12041 collect : function(dataIndex, allowNull, bypassFilter){
12042 var d = (bypassFilter === true && this.snapshot) ?
12043 this.snapshot.items : this.data.items;
12044 var v, sv, r = [], l = {};
12045 for(var i = 0, len = d.length; i < len; i++){
12046 v = d[i].data[dataIndex];
12048 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12057 * Revert to a view of the Record cache with no filtering applied.
12058 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12060 clearFilter : function(suppressEvent){
12061 if(this.snapshot && this.snapshot != this.data){
12062 this.data = this.snapshot;
12063 delete this.snapshot;
12064 if(suppressEvent !== true){
12065 this.fireEvent("datachanged", this);
12071 afterEdit : function(record){
12072 if(this.modified.indexOf(record) == -1){
12073 this.modified.push(record);
12075 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12079 afterReject : function(record){
12080 this.modified.remove(record);
12081 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12085 afterCommit : function(record){
12086 this.modified.remove(record);
12087 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12091 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12092 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12094 commitChanges : function(){
12095 var m = this.modified.slice(0);
12096 this.modified = [];
12097 for(var i = 0, len = m.length; i < len; i++){
12103 * Cancel outstanding changes on all changed records.
12105 rejectChanges : function(){
12106 var m = this.modified.slice(0);
12107 this.modified = [];
12108 for(var i = 0, len = m.length; i < len; i++){
12113 onMetaChange : function(meta, rtype, o){
12114 this.recordType = rtype;
12115 this.fields = rtype.prototype.fields;
12116 delete this.snapshot;
12117 this.sortInfo = meta.sortInfo || this.sortInfo;
12118 this.modified = [];
12119 this.fireEvent('metachange', this, this.reader.meta);
12122 moveIndex : function(data, type)
12124 var index = this.indexOf(data);
12126 var newIndex = index + type;
12130 this.insert(newIndex, data);
12135 * Ext JS Library 1.1.1
12136 * Copyright(c) 2006-2007, Ext JS, LLC.
12138 * Originally Released Under LGPL - original licence link has changed is not relivant.
12141 * <script type="text/javascript">
12145 * @class Roo.data.SimpleStore
12146 * @extends Roo.data.Store
12147 * Small helper class to make creating Stores from Array data easier.
12148 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12149 * @cfg {Array} fields An array of field definition objects, or field name strings.
12150 * @cfg {Array} data The multi-dimensional array of data
12152 * @param {Object} config
12154 Roo.data.SimpleStore = function(config){
12155 Roo.data.SimpleStore.superclass.constructor.call(this, {
12157 reader: new Roo.data.ArrayReader({
12160 Roo.data.Record.create(config.fields)
12162 proxy : new Roo.data.MemoryProxy(config.data)
12166 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12168 * Ext JS Library 1.1.1
12169 * Copyright(c) 2006-2007, Ext JS, LLC.
12171 * Originally Released Under LGPL - original licence link has changed is not relivant.
12174 * <script type="text/javascript">
12179 * @extends Roo.data.Store
12180 * @class Roo.data.JsonStore
12181 * Small helper class to make creating Stores for JSON data easier. <br/>
12183 var store = new Roo.data.JsonStore({
12184 url: 'get-images.php',
12186 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12189 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12190 * JsonReader and HttpProxy (unless inline data is provided).</b>
12191 * @cfg {Array} fields An array of field definition objects, or field name strings.
12193 * @param {Object} config
12195 Roo.data.JsonStore = function(c){
12196 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12197 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12198 reader: new Roo.data.JsonReader(c, c.fields)
12201 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12203 * Ext JS Library 1.1.1
12204 * Copyright(c) 2006-2007, Ext JS, LLC.
12206 * Originally Released Under LGPL - original licence link has changed is not relivant.
12209 * <script type="text/javascript">
12213 Roo.data.Field = function(config){
12214 if(typeof config == "string"){
12215 config = {name: config};
12217 Roo.apply(this, config);
12220 this.type = "auto";
12223 var st = Roo.data.SortTypes;
12224 // named sortTypes are supported, here we look them up
12225 if(typeof this.sortType == "string"){
12226 this.sortType = st[this.sortType];
12229 // set default sortType for strings and dates
12230 if(!this.sortType){
12233 this.sortType = st.asUCString;
12236 this.sortType = st.asDate;
12239 this.sortType = st.none;
12244 var stripRe = /[\$,%]/g;
12246 // prebuilt conversion function for this field, instead of
12247 // switching every time we're reading a value
12249 var cv, dateFormat = this.dateFormat;
12254 cv = function(v){ return v; };
12257 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12261 return v !== undefined && v !== null && v !== '' ?
12262 parseInt(String(v).replace(stripRe, ""), 10) : '';
12267 return v !== undefined && v !== null && v !== '' ?
12268 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12273 cv = function(v){ return v === true || v === "true" || v == 1; };
12280 if(v instanceof Date){
12284 if(dateFormat == "timestamp"){
12285 return new Date(v*1000);
12287 return Date.parseDate(v, dateFormat);
12289 var parsed = Date.parse(v);
12290 return parsed ? new Date(parsed) : null;
12299 Roo.data.Field.prototype = {
12307 * Ext JS Library 1.1.1
12308 * Copyright(c) 2006-2007, Ext JS, LLC.
12310 * Originally Released Under LGPL - original licence link has changed is not relivant.
12313 * <script type="text/javascript">
12316 // Base class for reading structured data from a data source. This class is intended to be
12317 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12320 * @class Roo.data.DataReader
12321 * Base class for reading structured data from a data source. This class is intended to be
12322 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12325 Roo.data.DataReader = function(meta, recordType){
12329 this.recordType = recordType instanceof Array ?
12330 Roo.data.Record.create(recordType) : recordType;
12333 Roo.data.DataReader.prototype = {
12335 * Create an empty record
12336 * @param {Object} data (optional) - overlay some values
12337 * @return {Roo.data.Record} record created.
12339 newRow : function(d) {
12341 this.recordType.prototype.fields.each(function(c) {
12343 case 'int' : da[c.name] = 0; break;
12344 case 'date' : da[c.name] = new Date(); break;
12345 case 'float' : da[c.name] = 0.0; break;
12346 case 'boolean' : da[c.name] = false; break;
12347 default : da[c.name] = ""; break;
12351 return new this.recordType(Roo.apply(da, d));
12356 * Ext JS Library 1.1.1
12357 * Copyright(c) 2006-2007, Ext JS, LLC.
12359 * Originally Released Under LGPL - original licence link has changed is not relivant.
12362 * <script type="text/javascript">
12366 * @class Roo.data.DataProxy
12367 * @extends Roo.data.Observable
12368 * This class is an abstract base class for implementations which provide retrieval of
12369 * unformatted data objects.<br>
12371 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12372 * (of the appropriate type which knows how to parse the data object) to provide a block of
12373 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12375 * Custom implementations must implement the load method as described in
12376 * {@link Roo.data.HttpProxy#load}.
12378 Roo.data.DataProxy = function(){
12381 * @event beforeload
12382 * Fires before a network request is made to retrieve a data object.
12383 * @param {Object} This DataProxy object.
12384 * @param {Object} params The params parameter to the load function.
12389 * Fires before the load method's callback is called.
12390 * @param {Object} This DataProxy object.
12391 * @param {Object} o The data object.
12392 * @param {Object} arg The callback argument object passed to the load function.
12396 * @event loadexception
12397 * Fires if an Exception occurs during data retrieval.
12398 * @param {Object} This DataProxy object.
12399 * @param {Object} o The data object.
12400 * @param {Object} arg The callback argument object passed to the load function.
12401 * @param {Object} e The Exception.
12403 loadexception : true
12405 Roo.data.DataProxy.superclass.constructor.call(this);
12408 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12411 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12415 * Ext JS Library 1.1.1
12416 * Copyright(c) 2006-2007, Ext JS, LLC.
12418 * Originally Released Under LGPL - original licence link has changed is not relivant.
12421 * <script type="text/javascript">
12424 * @class Roo.data.MemoryProxy
12425 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12426 * to the Reader when its load method is called.
12428 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12430 Roo.data.MemoryProxy = function(data){
12434 Roo.data.MemoryProxy.superclass.constructor.call(this);
12438 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12441 * Load data from the requested source (in this case an in-memory
12442 * data object passed to the constructor), read the data object into
12443 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12444 * process that block using the passed callback.
12445 * @param {Object} params This parameter is not used by the MemoryProxy class.
12446 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12447 * object into a block of Roo.data.Records.
12448 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12449 * The function must be passed <ul>
12450 * <li>The Record block object</li>
12451 * <li>The "arg" argument from the load function</li>
12452 * <li>A boolean success indicator</li>
12454 * @param {Object} scope The scope in which to call the callback
12455 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12457 load : function(params, reader, callback, scope, arg){
12458 params = params || {};
12461 result = reader.readRecords(params.data ? params.data :this.data);
12463 this.fireEvent("loadexception", this, arg, null, e);
12464 callback.call(scope, null, arg, false);
12467 callback.call(scope, result, arg, true);
12471 update : function(params, records){
12476 * Ext JS Library 1.1.1
12477 * Copyright(c) 2006-2007, Ext JS, LLC.
12479 * Originally Released Under LGPL - original licence link has changed is not relivant.
12482 * <script type="text/javascript">
12485 * @class Roo.data.HttpProxy
12486 * @extends Roo.data.DataProxy
12487 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12488 * configured to reference a certain URL.<br><br>
12490 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12491 * from which the running page was served.<br><br>
12493 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12495 * Be aware that to enable the browser to parse an XML document, the server must set
12496 * the Content-Type header in the HTTP response to "text/xml".
12498 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12499 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12500 * will be used to make the request.
12502 Roo.data.HttpProxy = function(conn){
12503 Roo.data.HttpProxy.superclass.constructor.call(this);
12504 // is conn a conn config or a real conn?
12506 this.useAjax = !conn || !conn.events;
12510 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12511 // thse are take from connection...
12514 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12517 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12518 * extra parameters to each request made by this object. (defaults to undefined)
12521 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12522 * to each request made by this object. (defaults to undefined)
12525 * @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)
12528 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12531 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12537 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12541 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12542 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12543 * a finer-grained basis than the DataProxy events.
12545 getConnection : function(){
12546 return this.useAjax ? Roo.Ajax : this.conn;
12550 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12551 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12552 * process that block using the passed callback.
12553 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12554 * for the request to the remote server.
12555 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12556 * object into a block of Roo.data.Records.
12557 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12558 * The function must be passed <ul>
12559 * <li>The Record block object</li>
12560 * <li>The "arg" argument from the load function</li>
12561 * <li>A boolean success indicator</li>
12563 * @param {Object} scope The scope in which to call the callback
12564 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12566 load : function(params, reader, callback, scope, arg){
12567 if(this.fireEvent("beforeload", this, params) !== false){
12569 params : params || {},
12571 callback : callback,
12576 callback : this.loadResponse,
12580 Roo.applyIf(o, this.conn);
12581 if(this.activeRequest){
12582 Roo.Ajax.abort(this.activeRequest);
12584 this.activeRequest = Roo.Ajax.request(o);
12586 this.conn.request(o);
12589 callback.call(scope||this, null, arg, false);
12594 loadResponse : function(o, success, response){
12595 delete this.activeRequest;
12597 this.fireEvent("loadexception", this, o, response);
12598 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12603 result = o.reader.read(response);
12605 this.fireEvent("loadexception", this, o, response, e);
12606 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12610 this.fireEvent("load", this, o, o.request.arg);
12611 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12615 update : function(dataSet){
12620 updateResponse : function(dataSet){
12625 * Ext JS Library 1.1.1
12626 * Copyright(c) 2006-2007, Ext JS, LLC.
12628 * Originally Released Under LGPL - original licence link has changed is not relivant.
12631 * <script type="text/javascript">
12635 * @class Roo.data.ScriptTagProxy
12636 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12637 * other than the originating domain of the running page.<br><br>
12639 * <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
12640 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12642 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12643 * source code that is used as the source inside a <script> tag.<br><br>
12645 * In order for the browser to process the returned data, the server must wrap the data object
12646 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12647 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12648 * depending on whether the callback name was passed:
12651 boolean scriptTag = false;
12652 String cb = request.getParameter("callback");
12655 response.setContentType("text/javascript");
12657 response.setContentType("application/x-json");
12659 Writer out = response.getWriter();
12661 out.write(cb + "(");
12663 out.print(dataBlock.toJsonString());
12670 * @param {Object} config A configuration object.
12672 Roo.data.ScriptTagProxy = function(config){
12673 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12674 Roo.apply(this, config);
12675 this.head = document.getElementsByTagName("head")[0];
12678 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12680 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12682 * @cfg {String} url The URL from which to request the data object.
12685 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12689 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12690 * the server the name of the callback function set up by the load call to process the returned data object.
12691 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12692 * javascript output which calls this named function passing the data object as its only parameter.
12694 callbackParam : "callback",
12696 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12697 * name to the request.
12702 * Load data from the configured URL, read the data object into
12703 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12704 * process that block using the passed callback.
12705 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12706 * for the request to the remote server.
12707 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12708 * object into a block of Roo.data.Records.
12709 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12710 * The function must be passed <ul>
12711 * <li>The Record block object</li>
12712 * <li>The "arg" argument from the load function</li>
12713 * <li>A boolean success indicator</li>
12715 * @param {Object} scope The scope in which to call the callback
12716 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12718 load : function(params, reader, callback, scope, arg){
12719 if(this.fireEvent("beforeload", this, params) !== false){
12721 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12723 var url = this.url;
12724 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12726 url += "&_dc=" + (new Date().getTime());
12728 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12731 cb : "stcCallback"+transId,
12732 scriptId : "stcScript"+transId,
12736 callback : callback,
12742 window[trans.cb] = function(o){
12743 conn.handleResponse(o, trans);
12746 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12748 if(this.autoAbort !== false){
12752 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12754 var script = document.createElement("script");
12755 script.setAttribute("src", url);
12756 script.setAttribute("type", "text/javascript");
12757 script.setAttribute("id", trans.scriptId);
12758 this.head.appendChild(script);
12760 this.trans = trans;
12762 callback.call(scope||this, null, arg, false);
12767 isLoading : function(){
12768 return this.trans ? true : false;
12772 * Abort the current server request.
12774 abort : function(){
12775 if(this.isLoading()){
12776 this.destroyTrans(this.trans);
12781 destroyTrans : function(trans, isLoaded){
12782 this.head.removeChild(document.getElementById(trans.scriptId));
12783 clearTimeout(trans.timeoutId);
12785 window[trans.cb] = undefined;
12787 delete window[trans.cb];
12790 // if hasn't been loaded, wait for load to remove it to prevent script error
12791 window[trans.cb] = function(){
12792 window[trans.cb] = undefined;
12794 delete window[trans.cb];
12801 handleResponse : function(o, trans){
12802 this.trans = false;
12803 this.destroyTrans(trans, true);
12806 result = trans.reader.readRecords(o);
12808 this.fireEvent("loadexception", this, o, trans.arg, e);
12809 trans.callback.call(trans.scope||window, null, trans.arg, false);
12812 this.fireEvent("load", this, o, trans.arg);
12813 trans.callback.call(trans.scope||window, result, trans.arg, true);
12817 handleFailure : function(trans){
12818 this.trans = false;
12819 this.destroyTrans(trans, false);
12820 this.fireEvent("loadexception", this, null, trans.arg);
12821 trans.callback.call(trans.scope||window, null, trans.arg, false);
12825 * Ext JS Library 1.1.1
12826 * Copyright(c) 2006-2007, Ext JS, LLC.
12828 * Originally Released Under LGPL - original licence link has changed is not relivant.
12831 * <script type="text/javascript">
12835 * @class Roo.data.JsonReader
12836 * @extends Roo.data.DataReader
12837 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12838 * based on mappings in a provided Roo.data.Record constructor.
12840 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12841 * in the reply previously.
12846 var RecordDef = Roo.data.Record.create([
12847 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12848 {name: 'occupation'} // This field will use "occupation" as the mapping.
12850 var myReader = new Roo.data.JsonReader({
12851 totalProperty: "results", // The property which contains the total dataset size (optional)
12852 root: "rows", // The property which contains an Array of row objects
12853 id: "id" // The property within each row object that provides an ID for the record (optional)
12857 * This would consume a JSON file like this:
12859 { 'results': 2, 'rows': [
12860 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12861 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12864 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12865 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12866 * paged from the remote server.
12867 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12868 * @cfg {String} root name of the property which contains the Array of row objects.
12869 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12870 * @cfg {Array} fields Array of field definition objects
12872 * Create a new JsonReader
12873 * @param {Object} meta Metadata configuration options
12874 * @param {Object} recordType Either an Array of field definition objects,
12875 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12877 Roo.data.JsonReader = function(meta, recordType){
12880 // set some defaults:
12881 Roo.applyIf(meta, {
12882 totalProperty: 'total',
12883 successProperty : 'success',
12888 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12890 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12893 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12894 * Used by Store query builder to append _requestMeta to params.
12897 metaFromRemote : false,
12899 * This method is only used by a DataProxy which has retrieved data from a remote server.
12900 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12901 * @return {Object} data A data block which is used by an Roo.data.Store object as
12902 * a cache of Roo.data.Records.
12904 read : function(response){
12905 var json = response.responseText;
12907 var o = /* eval:var:o */ eval("("+json+")");
12909 throw {message: "JsonReader.read: Json object not found"};
12915 this.metaFromRemote = true;
12916 this.meta = o.metaData;
12917 this.recordType = Roo.data.Record.create(o.metaData.fields);
12918 this.onMetaChange(this.meta, this.recordType, o);
12920 return this.readRecords(o);
12923 // private function a store will implement
12924 onMetaChange : function(meta, recordType, o){
12931 simpleAccess: function(obj, subsc) {
12938 getJsonAccessor: function(){
12940 return function(expr) {
12942 return(re.test(expr))
12943 ? new Function("obj", "return obj." + expr)
12948 return Roo.emptyFn;
12953 * Create a data block containing Roo.data.Records from an XML document.
12954 * @param {Object} o An object which contains an Array of row objects in the property specified
12955 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12956 * which contains the total size of the dataset.
12957 * @return {Object} data A data block which is used by an Roo.data.Store object as
12958 * a cache of Roo.data.Records.
12960 readRecords : function(o){
12962 * After any data loads, the raw JSON data is available for further custom processing.
12966 var s = this.meta, Record = this.recordType,
12967 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12969 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12971 if(s.totalProperty) {
12972 this.getTotal = this.getJsonAccessor(s.totalProperty);
12974 if(s.successProperty) {
12975 this.getSuccess = this.getJsonAccessor(s.successProperty);
12977 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12979 var g = this.getJsonAccessor(s.id);
12980 this.getId = function(rec) {
12982 return (r === undefined || r === "") ? null : r;
12985 this.getId = function(){return null;};
12988 for(var jj = 0; jj < fl; jj++){
12990 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12991 this.ef[jj] = this.getJsonAccessor(map);
12995 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12996 if(s.totalProperty){
12997 var vt = parseInt(this.getTotal(o), 10);
13002 if(s.successProperty){
13003 var vs = this.getSuccess(o);
13004 if(vs === false || vs === 'false'){
13009 for(var i = 0; i < c; i++){
13012 var id = this.getId(n);
13013 for(var j = 0; j < fl; j++){
13015 var v = this.ef[j](n);
13017 Roo.log('missing convert for ' + f.name);
13021 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13023 var record = new Record(values, id);
13025 records[i] = record;
13031 totalRecords : totalRecords
13036 * Ext JS Library 1.1.1
13037 * Copyright(c) 2006-2007, Ext JS, LLC.
13039 * Originally Released Under LGPL - original licence link has changed is not relivant.
13042 * <script type="text/javascript">
13046 * @class Roo.data.ArrayReader
13047 * @extends Roo.data.DataReader
13048 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13049 * Each element of that Array represents a row of data fields. The
13050 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13051 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13055 var RecordDef = Roo.data.Record.create([
13056 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13057 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13059 var myReader = new Roo.data.ArrayReader({
13060 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13064 * This would consume an Array like this:
13066 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13070 * Create a new JsonReader
13071 * @param {Object} meta Metadata configuration options.
13072 * @param {Object|Array} recordType Either an Array of field definition objects
13074 * @cfg {Array} fields Array of field definition objects
13075 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13076 * as specified to {@link Roo.data.Record#create},
13077 * or an {@link Roo.data.Record} object
13080 * created using {@link Roo.data.Record#create}.
13082 Roo.data.ArrayReader = function(meta, recordType){
13085 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13088 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13090 * Create a data block containing Roo.data.Records from an XML document.
13091 * @param {Object} o An Array of row objects which represents the dataset.
13092 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13093 * a cache of Roo.data.Records.
13095 readRecords : function(o){
13096 var sid = this.meta ? this.meta.id : null;
13097 var recordType = this.recordType, fields = recordType.prototype.fields;
13100 for(var i = 0; i < root.length; i++){
13103 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13104 for(var j = 0, jlen = fields.length; j < jlen; j++){
13105 var f = fields.items[j];
13106 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13107 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13109 values[f.name] = v;
13111 var record = new recordType(values, id);
13113 records[records.length] = record;
13117 totalRecords : records.length
13126 * @class Roo.bootstrap.ComboBox
13127 * @extends Roo.bootstrap.TriggerField
13128 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13129 * @cfg {Boolean} append (true|false) default false
13130 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13131 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13132 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13133 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13134 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13135 * @cfg {Boolean} animate default true
13136 * @cfg {Boolean} emptyResultText only for touch device
13137 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13138 * @cfg {String} emptyTitle default ''
13140 * Create a new ComboBox.
13141 * @param {Object} config Configuration options
13143 Roo.bootstrap.ComboBox = function(config){
13144 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13148 * Fires when the dropdown list is expanded
13149 * @param {Roo.bootstrap.ComboBox} combo This combo box
13154 * Fires when the dropdown list is collapsed
13155 * @param {Roo.bootstrap.ComboBox} combo This combo box
13159 * @event beforeselect
13160 * Fires before a list item is selected. Return false to cancel the selection.
13161 * @param {Roo.bootstrap.ComboBox} combo This combo box
13162 * @param {Roo.data.Record} record The data record returned from the underlying store
13163 * @param {Number} index The index of the selected item in the dropdown list
13165 'beforeselect' : true,
13168 * Fires when a list item is selected
13169 * @param {Roo.bootstrap.ComboBox} combo This combo box
13170 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13171 * @param {Number} index The index of the selected item in the dropdown list
13175 * @event beforequery
13176 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13177 * The event object passed has these properties:
13178 * @param {Roo.bootstrap.ComboBox} combo This combo box
13179 * @param {String} query The query
13180 * @param {Boolean} forceAll true to force "all" query
13181 * @param {Boolean} cancel true to cancel the query
13182 * @param {Object} e The query event object
13184 'beforequery': true,
13187 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13188 * @param {Roo.bootstrap.ComboBox} combo This combo box
13193 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13194 * @param {Roo.bootstrap.ComboBox} combo This combo box
13195 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13200 * Fires when the remove value from the combobox array
13201 * @param {Roo.bootstrap.ComboBox} combo This combo box
13205 * @event afterremove
13206 * Fires when the remove value from the combobox array
13207 * @param {Roo.bootstrap.ComboBox} combo This combo box
13209 'afterremove' : true,
13211 * @event specialfilter
13212 * Fires when specialfilter
13213 * @param {Roo.bootstrap.ComboBox} combo This combo box
13215 'specialfilter' : true,
13218 * Fires when tick the element
13219 * @param {Roo.bootstrap.ComboBox} combo This combo box
13223 * @event touchviewdisplay
13224 * Fires when touch view require special display (default is using displayField)
13225 * @param {Roo.bootstrap.ComboBox} combo This combo box
13226 * @param {Object} cfg set html .
13228 'touchviewdisplay' : true
13233 this.tickItems = [];
13235 this.selectedIndex = -1;
13236 if(this.mode == 'local'){
13237 if(config.queryDelay === undefined){
13238 this.queryDelay = 10;
13240 if(config.minChars === undefined){
13246 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13249 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13250 * rendering into an Roo.Editor, defaults to false)
13253 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13254 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13257 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13260 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13261 * the dropdown list (defaults to undefined, with no header element)
13265 * @cfg {String/Roo.Template} tpl The template to use to render the output
13269 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13271 listWidth: undefined,
13273 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13274 * mode = 'remote' or 'text' if mode = 'local')
13276 displayField: undefined,
13279 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13280 * mode = 'remote' or 'value' if mode = 'local').
13281 * Note: use of a valueField requires the user make a selection
13282 * in order for a value to be mapped.
13284 valueField: undefined,
13286 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13291 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13292 * field's data value (defaults to the underlying DOM element's name)
13294 hiddenName: undefined,
13296 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13300 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13302 selectedClass: 'active',
13305 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13309 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13310 * anchor positions (defaults to 'tl-bl')
13312 listAlign: 'tl-bl?',
13314 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13318 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13319 * query specified by the allQuery config option (defaults to 'query')
13321 triggerAction: 'query',
13323 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13324 * (defaults to 4, does not apply if editable = false)
13328 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13329 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13333 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13334 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13338 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13339 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13343 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13344 * when editable = true (defaults to false)
13346 selectOnFocus:false,
13348 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13350 queryParam: 'query',
13352 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13353 * when mode = 'remote' (defaults to 'Loading...')
13355 loadingText: 'Loading...',
13357 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13361 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13365 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13366 * traditional select (defaults to true)
13370 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13374 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13378 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13379 * listWidth has a higher value)
13383 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13384 * allow the user to set arbitrary text into the field (defaults to false)
13386 forceSelection:false,
13388 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13389 * if typeAhead = true (defaults to 250)
13391 typeAheadDelay : 250,
13393 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13394 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13396 valueNotFoundText : undefined,
13398 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13400 blockFocus : false,
13403 * @cfg {Boolean} disableClear Disable showing of clear button.
13405 disableClear : false,
13407 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13409 alwaysQuery : false,
13412 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13417 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13419 invalidClass : "has-warning",
13422 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13424 validClass : "has-success",
13427 * @cfg {Boolean} specialFilter (true|false) special filter default false
13429 specialFilter : false,
13432 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13434 mobileTouchView : true,
13437 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13439 useNativeIOS : false,
13442 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13444 mobile_restrict_height : false,
13446 ios_options : false,
13458 btnPosition : 'right',
13459 triggerList : true,
13460 showToggleBtn : true,
13462 emptyResultText: 'Empty',
13463 triggerText : 'Select',
13466 // element that contains real text value.. (when hidden is used..)
13468 getAutoCreate : function()
13473 * Render classic select for iso
13476 if(Roo.isIOS && this.useNativeIOS){
13477 cfg = this.getAutoCreateNativeIOS();
13485 if(Roo.isTouch && this.mobileTouchView){
13486 cfg = this.getAutoCreateTouchView();
13493 if(!this.tickable){
13494 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13499 * ComboBox with tickable selections
13502 var align = this.labelAlign || this.parentLabelAlign();
13505 cls : 'form-group roo-combobox-tickable' //input-group
13508 var btn_text_select = '';
13509 var btn_text_done = '';
13510 var btn_text_cancel = '';
13512 if (this.btn_text_show) {
13513 btn_text_select = 'Select';
13514 btn_text_done = 'Done';
13515 btn_text_cancel = 'Cancel';
13520 cls : 'tickable-buttons',
13525 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13526 //html : this.triggerText
13527 html: btn_text_select
13533 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13535 html: btn_text_done
13541 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13543 html: btn_text_cancel
13549 buttons.cn.unshift({
13551 cls: 'roo-select2-search-field-input'
13557 Roo.each(buttons.cn, function(c){
13559 c.cls += ' btn-' + _this.size;
13562 if (_this.disabled) {
13569 style : 'display: contents',
13574 cls: 'form-hidden-field'
13578 cls: 'roo-select2-choices',
13582 cls: 'roo-select2-search-field',
13593 cls: 'roo-select2-container input-group roo-select2-container-multi',
13599 // cls: 'typeahead typeahead-long dropdown-menu',
13600 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13605 if(this.hasFeedback && !this.allowBlank){
13609 cls: 'glyphicon form-control-feedback'
13612 combobox.cn.push(feedback);
13617 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13618 tooltip : 'This field is required'
13620 if (Roo.bootstrap.version == 4) {
13623 style : 'display:none'
13626 if (align ==='left' && this.fieldLabel.length) {
13628 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13635 cls : 'control-label col-form-label',
13636 html : this.fieldLabel
13648 var labelCfg = cfg.cn[1];
13649 var contentCfg = cfg.cn[2];
13652 if(this.indicatorpos == 'right'){
13658 cls : 'control-label col-form-label',
13662 html : this.fieldLabel
13678 labelCfg = cfg.cn[0];
13679 contentCfg = cfg.cn[1];
13683 if(this.labelWidth > 12){
13684 labelCfg.style = "width: " + this.labelWidth + 'px';
13687 if(this.labelWidth < 13 && this.labelmd == 0){
13688 this.labelmd = this.labelWidth;
13691 if(this.labellg > 0){
13692 labelCfg.cls += ' col-lg-' + this.labellg;
13693 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13696 if(this.labelmd > 0){
13697 labelCfg.cls += ' col-md-' + this.labelmd;
13698 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13701 if(this.labelsm > 0){
13702 labelCfg.cls += ' col-sm-' + this.labelsm;
13703 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13706 if(this.labelxs > 0){
13707 labelCfg.cls += ' col-xs-' + this.labelxs;
13708 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13712 } else if ( this.fieldLabel.length) {
13713 // Roo.log(" label");
13718 //cls : 'input-group-addon',
13719 html : this.fieldLabel
13724 if(this.indicatorpos == 'right'){
13728 //cls : 'input-group-addon',
13729 html : this.fieldLabel
13739 // Roo.log(" no label && no align");
13746 ['xs','sm','md','lg'].map(function(size){
13747 if (settings[size]) {
13748 cfg.cls += ' col-' + size + '-' + settings[size];
13756 _initEventsCalled : false,
13759 initEvents: function()
13761 if (this._initEventsCalled) { // as we call render... prevent looping...
13764 this._initEventsCalled = true;
13767 throw "can not find store for combo";
13770 this.indicator = this.indicatorEl();
13772 this.store = Roo.factory(this.store, Roo.data);
13773 this.store.parent = this;
13775 // if we are building from html. then this element is so complex, that we can not really
13776 // use the rendered HTML.
13777 // so we have to trash and replace the previous code.
13778 if (Roo.XComponent.build_from_html) {
13779 // remove this element....
13780 var e = this.el.dom, k=0;
13781 while (e ) { e = e.previousSibling; ++k;}
13786 this.rendered = false;
13788 this.render(this.parent().getChildContainer(true), k);
13791 if(Roo.isIOS && this.useNativeIOS){
13792 this.initIOSView();
13800 if(Roo.isTouch && this.mobileTouchView){
13801 this.initTouchView();
13806 this.initTickableEvents();
13810 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13812 if(this.hiddenName){
13814 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13816 this.hiddenField.dom.value =
13817 this.hiddenValue !== undefined ? this.hiddenValue :
13818 this.value !== undefined ? this.value : '';
13820 // prevent input submission
13821 this.el.dom.removeAttribute('name');
13822 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13827 // this.el.dom.setAttribute('autocomplete', 'off');
13830 var cls = 'x-combo-list';
13832 //this.list = new Roo.Layer({
13833 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13839 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13840 _this.list.setWidth(lw);
13843 this.list.on('mouseover', this.onViewOver, this);
13844 this.list.on('mousemove', this.onViewMove, this);
13845 this.list.on('scroll', this.onViewScroll, this);
13848 this.list.swallowEvent('mousewheel');
13849 this.assetHeight = 0;
13852 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13853 this.assetHeight += this.header.getHeight();
13856 this.innerList = this.list.createChild({cls:cls+'-inner'});
13857 this.innerList.on('mouseover', this.onViewOver, this);
13858 this.innerList.on('mousemove', this.onViewMove, this);
13859 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13861 if(this.allowBlank && !this.pageSize && !this.disableClear){
13862 this.footer = this.list.createChild({cls:cls+'-ft'});
13863 this.pageTb = new Roo.Toolbar(this.footer);
13867 this.footer = this.list.createChild({cls:cls+'-ft'});
13868 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13869 {pageSize: this.pageSize});
13873 if (this.pageTb && this.allowBlank && !this.disableClear) {
13875 this.pageTb.add(new Roo.Toolbar.Fill(), {
13876 cls: 'x-btn-icon x-btn-clear',
13878 handler: function()
13881 _this.clearValue();
13882 _this.onSelect(false, -1);
13887 this.assetHeight += this.footer.getHeight();
13892 this.tpl = Roo.bootstrap.version == 4 ?
13893 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13894 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13897 this.view = new Roo.View(this.list, this.tpl, {
13898 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13900 //this.view.wrapEl.setDisplayed(false);
13901 this.view.on('click', this.onViewClick, this);
13904 this.store.on('beforeload', this.onBeforeLoad, this);
13905 this.store.on('load', this.onLoad, this);
13906 this.store.on('loadexception', this.onLoadException, this);
13908 if(this.resizable){
13909 this.resizer = new Roo.Resizable(this.list, {
13910 pinned:true, handles:'se'
13912 this.resizer.on('resize', function(r, w, h){
13913 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13914 this.listWidth = w;
13915 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13916 this.restrictHeight();
13918 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13921 if(!this.editable){
13922 this.editable = true;
13923 this.setEditable(false);
13928 if (typeof(this.events.add.listeners) != 'undefined') {
13930 this.addicon = this.wrap.createChild(
13931 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13933 this.addicon.on('click', function(e) {
13934 this.fireEvent('add', this);
13937 if (typeof(this.events.edit.listeners) != 'undefined') {
13939 this.editicon = this.wrap.createChild(
13940 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13941 if (this.addicon) {
13942 this.editicon.setStyle('margin-left', '40px');
13944 this.editicon.on('click', function(e) {
13946 // we fire even if inothing is selected..
13947 this.fireEvent('edit', this, this.lastData );
13953 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13954 "up" : function(e){
13955 this.inKeyMode = true;
13959 "down" : function(e){
13960 if(!this.isExpanded()){
13961 this.onTriggerClick();
13963 this.inKeyMode = true;
13968 "enter" : function(e){
13969 // this.onViewClick();
13973 if(this.fireEvent("specialkey", this, e)){
13974 this.onViewClick(false);
13980 "esc" : function(e){
13984 "tab" : function(e){
13987 if(this.fireEvent("specialkey", this, e)){
13988 this.onViewClick(false);
13996 doRelay : function(foo, bar, hname){
13997 if(hname == 'down' || this.scope.isExpanded()){
13998 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14007 this.queryDelay = Math.max(this.queryDelay || 10,
14008 this.mode == 'local' ? 10 : 250);
14011 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14013 if(this.typeAhead){
14014 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14016 if(this.editable !== false){
14017 this.inputEl().on("keyup", this.onKeyUp, this);
14019 if(this.forceSelection){
14020 this.inputEl().on('blur', this.doForce, this);
14024 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14025 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14029 initTickableEvents: function()
14033 if(this.hiddenName){
14035 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14037 this.hiddenField.dom.value =
14038 this.hiddenValue !== undefined ? this.hiddenValue :
14039 this.value !== undefined ? this.value : '';
14041 // prevent input submission
14042 this.el.dom.removeAttribute('name');
14043 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14048 // this.list = this.el.select('ul.dropdown-menu',true).first();
14050 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14051 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14052 if(this.triggerList){
14053 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14056 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14057 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14059 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14060 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14062 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14063 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14065 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14066 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14067 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14070 this.cancelBtn.hide();
14075 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14076 _this.list.setWidth(lw);
14079 this.list.on('mouseover', this.onViewOver, this);
14080 this.list.on('mousemove', this.onViewMove, this);
14082 this.list.on('scroll', this.onViewScroll, this);
14085 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14086 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14089 this.view = new Roo.View(this.list, this.tpl, {
14094 selectedClass: this.selectedClass
14097 //this.view.wrapEl.setDisplayed(false);
14098 this.view.on('click', this.onViewClick, this);
14102 this.store.on('beforeload', this.onBeforeLoad, this);
14103 this.store.on('load', this.onLoad, this);
14104 this.store.on('loadexception', this.onLoadException, this);
14107 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14108 "up" : function(e){
14109 this.inKeyMode = true;
14113 "down" : function(e){
14114 this.inKeyMode = true;
14118 "enter" : function(e){
14119 if(this.fireEvent("specialkey", this, e)){
14120 this.onViewClick(false);
14126 "esc" : function(e){
14127 this.onTickableFooterButtonClick(e, false, false);
14130 "tab" : function(e){
14131 this.fireEvent("specialkey", this, e);
14133 this.onTickableFooterButtonClick(e, false, false);
14140 doRelay : function(e, fn, key){
14141 if(this.scope.isExpanded()){
14142 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14151 this.queryDelay = Math.max(this.queryDelay || 10,
14152 this.mode == 'local' ? 10 : 250);
14155 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14157 if(this.typeAhead){
14158 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14161 if(this.editable !== false){
14162 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14165 this.indicator = this.indicatorEl();
14167 if(this.indicator){
14168 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14169 this.indicator.hide();
14174 onDestroy : function(){
14176 this.view.setStore(null);
14177 this.view.el.removeAllListeners();
14178 this.view.el.remove();
14179 this.view.purgeListeners();
14182 this.list.dom.innerHTML = '';
14186 this.store.un('beforeload', this.onBeforeLoad, this);
14187 this.store.un('load', this.onLoad, this);
14188 this.store.un('loadexception', this.onLoadException, this);
14190 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14194 fireKey : function(e){
14195 if(e.isNavKeyPress() && !this.list.isVisible()){
14196 this.fireEvent("specialkey", this, e);
14201 onResize: function(w, h){
14202 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14204 // if(typeof w != 'number'){
14205 // // we do not handle it!?!?
14208 // var tw = this.trigger.getWidth();
14209 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14210 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14212 // this.inputEl().setWidth( this.adjustWidth('input', x));
14214 // //this.trigger.setStyle('left', x+'px');
14216 // if(this.list && this.listWidth === undefined){
14217 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14218 // this.list.setWidth(lw);
14219 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14227 * Allow or prevent the user from directly editing the field text. If false is passed,
14228 * the user will only be able to select from the items defined in the dropdown list. This method
14229 * is the runtime equivalent of setting the 'editable' config option at config time.
14230 * @param {Boolean} value True to allow the user to directly edit the field text
14232 setEditable : function(value){
14233 if(value == this.editable){
14236 this.editable = value;
14238 this.inputEl().dom.setAttribute('readOnly', true);
14239 this.inputEl().on('mousedown', this.onTriggerClick, this);
14240 this.inputEl().addClass('x-combo-noedit');
14242 this.inputEl().dom.setAttribute('readOnly', false);
14243 this.inputEl().un('mousedown', this.onTriggerClick, this);
14244 this.inputEl().removeClass('x-combo-noedit');
14250 onBeforeLoad : function(combo,opts){
14251 if(!this.hasFocus){
14255 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14257 this.restrictHeight();
14258 this.selectedIndex = -1;
14262 onLoad : function(){
14264 this.hasQuery = false;
14266 if(!this.hasFocus){
14270 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14271 this.loading.hide();
14274 if(this.store.getCount() > 0){
14277 this.restrictHeight();
14278 if(this.lastQuery == this.allQuery){
14279 if(this.editable && !this.tickable){
14280 this.inputEl().dom.select();
14284 !this.selectByValue(this.value, true) &&
14287 !this.store.lastOptions ||
14288 typeof(this.store.lastOptions.add) == 'undefined' ||
14289 this.store.lastOptions.add != true
14292 this.select(0, true);
14295 if(this.autoFocus){
14298 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14299 this.taTask.delay(this.typeAheadDelay);
14303 this.onEmptyResults();
14309 onLoadException : function()
14311 this.hasQuery = false;
14313 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14314 this.loading.hide();
14317 if(this.tickable && this.editable){
14322 // only causes errors at present
14323 //Roo.log(this.store.reader.jsonData);
14324 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14326 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14332 onTypeAhead : function(){
14333 if(this.store.getCount() > 0){
14334 var r = this.store.getAt(0);
14335 var newValue = r.data[this.displayField];
14336 var len = newValue.length;
14337 var selStart = this.getRawValue().length;
14339 if(selStart != len){
14340 this.setRawValue(newValue);
14341 this.selectText(selStart, newValue.length);
14347 onSelect : function(record, index){
14349 if(this.fireEvent('beforeselect', this, record, index) !== false){
14351 this.setFromData(index > -1 ? record.data : false);
14354 this.fireEvent('select', this, record, index);
14359 * Returns the currently selected field value or empty string if no value is set.
14360 * @return {String} value The selected value
14362 getValue : function()
14364 if(Roo.isIOS && this.useNativeIOS){
14365 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14369 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14372 if(this.valueField){
14373 return typeof this.value != 'undefined' ? this.value : '';
14375 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14379 getRawValue : function()
14381 if(Roo.isIOS && this.useNativeIOS){
14382 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14385 var v = this.inputEl().getValue();
14391 * Clears any text/value currently set in the field
14393 clearValue : function(){
14395 if(this.hiddenField){
14396 this.hiddenField.dom.value = '';
14399 this.setRawValue('');
14400 this.lastSelectionText = '';
14401 this.lastData = false;
14403 var close = this.closeTriggerEl();
14414 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14415 * will be displayed in the field. If the value does not match the data value of an existing item,
14416 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14417 * Otherwise the field will be blank (although the value will still be set).
14418 * @param {String} value The value to match
14420 setValue : function(v)
14422 if(Roo.isIOS && this.useNativeIOS){
14423 this.setIOSValue(v);
14433 if(this.valueField){
14434 var r = this.findRecord(this.valueField, v);
14436 text = r.data[this.displayField];
14437 }else if(this.valueNotFoundText !== undefined){
14438 text = this.valueNotFoundText;
14441 this.lastSelectionText = text;
14442 if(this.hiddenField){
14443 this.hiddenField.dom.value = v;
14445 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14448 var close = this.closeTriggerEl();
14451 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14457 * @property {Object} the last set data for the element
14462 * Sets the value of the field based on a object which is related to the record format for the store.
14463 * @param {Object} value the value to set as. or false on reset?
14465 setFromData : function(o){
14472 var dv = ''; // display value
14473 var vv = ''; // value value..
14475 if (this.displayField) {
14476 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14478 // this is an error condition!!!
14479 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14482 if(this.valueField){
14483 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14486 var close = this.closeTriggerEl();
14489 if(dv.length || vv * 1 > 0){
14491 this.blockFocus=true;
14497 if(this.hiddenField){
14498 this.hiddenField.dom.value = vv;
14500 this.lastSelectionText = dv;
14501 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14505 // no hidden field.. - we store the value in 'value', but still display
14506 // display field!!!!
14507 this.lastSelectionText = dv;
14508 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14515 reset : function(){
14516 // overridden so that last data is reset..
14523 this.setValue(this.originalValue);
14524 //this.clearInvalid();
14525 this.lastData = false;
14527 this.view.clearSelections();
14533 findRecord : function(prop, value){
14535 if(this.store.getCount() > 0){
14536 this.store.each(function(r){
14537 if(r.data[prop] == value){
14547 getName: function()
14549 // returns hidden if it's set..
14550 if (!this.rendered) {return ''};
14551 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14555 onViewMove : function(e, t){
14556 this.inKeyMode = false;
14560 onViewOver : function(e, t){
14561 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14564 var item = this.view.findItemFromChild(t);
14567 var index = this.view.indexOf(item);
14568 this.select(index, false);
14573 onViewClick : function(view, doFocus, el, e)
14575 var index = this.view.getSelectedIndexes()[0];
14577 var r = this.store.getAt(index);
14581 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14588 Roo.each(this.tickItems, function(v,k){
14590 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14592 _this.tickItems.splice(k, 1);
14594 if(typeof(e) == 'undefined' && view == false){
14595 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14607 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14608 this.tickItems.push(r.data);
14611 if(typeof(e) == 'undefined' && view == false){
14612 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14619 this.onSelect(r, index);
14621 if(doFocus !== false && !this.blockFocus){
14622 this.inputEl().focus();
14627 restrictHeight : function(){
14628 //this.innerList.dom.style.height = '';
14629 //var inner = this.innerList.dom;
14630 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14631 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14632 //this.list.beginUpdate();
14633 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14634 this.list.alignTo(this.inputEl(), this.listAlign);
14635 this.list.alignTo(this.inputEl(), this.listAlign);
14636 //this.list.endUpdate();
14640 onEmptyResults : function(){
14642 if(this.tickable && this.editable){
14643 this.hasFocus = false;
14644 this.restrictHeight();
14652 * Returns true if the dropdown list is expanded, else false.
14654 isExpanded : function(){
14655 return this.list.isVisible();
14659 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14660 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14661 * @param {String} value The data value of the item to select
14662 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14663 * selected item if it is not currently in view (defaults to true)
14664 * @return {Boolean} True if the value matched an item in the list, else false
14666 selectByValue : function(v, scrollIntoView){
14667 if(v !== undefined && v !== null){
14668 var r = this.findRecord(this.valueField || this.displayField, v);
14670 this.select(this.store.indexOf(r), scrollIntoView);
14678 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14679 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14680 * @param {Number} index The zero-based index of the list item to select
14681 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14682 * selected item if it is not currently in view (defaults to true)
14684 select : function(index, scrollIntoView){
14685 this.selectedIndex = index;
14686 this.view.select(index);
14687 if(scrollIntoView !== false){
14688 var el = this.view.getNode(index);
14690 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14693 this.list.scrollChildIntoView(el, false);
14699 selectNext : function(){
14700 var ct = this.store.getCount();
14702 if(this.selectedIndex == -1){
14704 }else if(this.selectedIndex < ct-1){
14705 this.select(this.selectedIndex+1);
14711 selectPrev : function(){
14712 var ct = this.store.getCount();
14714 if(this.selectedIndex == -1){
14716 }else if(this.selectedIndex != 0){
14717 this.select(this.selectedIndex-1);
14723 onKeyUp : function(e){
14724 if(this.editable !== false && !e.isSpecialKey()){
14725 this.lastKey = e.getKey();
14726 this.dqTask.delay(this.queryDelay);
14731 validateBlur : function(){
14732 return !this.list || !this.list.isVisible();
14736 initQuery : function(){
14738 var v = this.getRawValue();
14740 if(this.tickable && this.editable){
14741 v = this.tickableInputEl().getValue();
14748 doForce : function(){
14749 if(this.inputEl().dom.value.length > 0){
14750 this.inputEl().dom.value =
14751 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14757 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14758 * query allowing the query action to be canceled if needed.
14759 * @param {String} query The SQL query to execute
14760 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14761 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14762 * saved in the current store (defaults to false)
14764 doQuery : function(q, forceAll){
14766 if(q === undefined || q === null){
14771 forceAll: forceAll,
14775 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14780 forceAll = qe.forceAll;
14781 if(forceAll === true || (q.length >= this.minChars)){
14783 this.hasQuery = true;
14785 if(this.lastQuery != q || this.alwaysQuery){
14786 this.lastQuery = q;
14787 if(this.mode == 'local'){
14788 this.selectedIndex = -1;
14790 this.store.clearFilter();
14793 if(this.specialFilter){
14794 this.fireEvent('specialfilter', this);
14799 this.store.filter(this.displayField, q);
14802 this.store.fireEvent("datachanged", this.store);
14809 this.store.baseParams[this.queryParam] = q;
14811 var options = {params : this.getParams(q)};
14814 options.add = true;
14815 options.params.start = this.page * this.pageSize;
14818 this.store.load(options);
14821 * this code will make the page width larger, at the beginning, the list not align correctly,
14822 * we should expand the list on onLoad
14823 * so command out it
14828 this.selectedIndex = -1;
14833 this.loadNext = false;
14837 getParams : function(q){
14839 //p[this.queryParam] = q;
14843 p.limit = this.pageSize;
14849 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14851 collapse : function(){
14852 if(!this.isExpanded()){
14858 this.hasFocus = false;
14862 this.cancelBtn.hide();
14863 this.trigger.show();
14866 this.tickableInputEl().dom.value = '';
14867 this.tickableInputEl().blur();
14872 Roo.get(document).un('mousedown', this.collapseIf, this);
14873 Roo.get(document).un('mousewheel', this.collapseIf, this);
14874 if (!this.editable) {
14875 Roo.get(document).un('keydown', this.listKeyPress, this);
14877 this.fireEvent('collapse', this);
14883 collapseIf : function(e){
14884 var in_combo = e.within(this.el);
14885 var in_list = e.within(this.list);
14886 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14888 if (in_combo || in_list || is_list) {
14889 //e.stopPropagation();
14894 this.onTickableFooterButtonClick(e, false, false);
14902 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14904 expand : function(){
14906 if(this.isExpanded() || !this.hasFocus){
14910 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14911 this.list.setWidth(lw);
14917 this.restrictHeight();
14921 this.tickItems = Roo.apply([], this.item);
14924 this.cancelBtn.show();
14925 this.trigger.hide();
14928 this.tickableInputEl().focus();
14933 Roo.get(document).on('mousedown', this.collapseIf, this);
14934 Roo.get(document).on('mousewheel', this.collapseIf, this);
14935 if (!this.editable) {
14936 Roo.get(document).on('keydown', this.listKeyPress, this);
14939 this.fireEvent('expand', this);
14943 // Implements the default empty TriggerField.onTriggerClick function
14944 onTriggerClick : function(e)
14946 Roo.log('trigger click');
14948 if(this.disabled || !this.triggerList){
14953 this.loadNext = false;
14955 if(this.isExpanded()){
14957 if (!this.blockFocus) {
14958 this.inputEl().focus();
14962 this.hasFocus = true;
14963 if(this.triggerAction == 'all') {
14964 this.doQuery(this.allQuery, true);
14966 this.doQuery(this.getRawValue());
14968 if (!this.blockFocus) {
14969 this.inputEl().focus();
14974 onTickableTriggerClick : function(e)
14981 this.loadNext = false;
14982 this.hasFocus = true;
14984 if(this.triggerAction == 'all') {
14985 this.doQuery(this.allQuery, true);
14987 this.doQuery(this.getRawValue());
14991 onSearchFieldClick : function(e)
14993 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14994 this.onTickableFooterButtonClick(e, false, false);
14998 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
15003 this.loadNext = false;
15004 this.hasFocus = true;
15006 if(this.triggerAction == 'all') {
15007 this.doQuery(this.allQuery, true);
15009 this.doQuery(this.getRawValue());
15013 listKeyPress : function(e)
15015 //Roo.log('listkeypress');
15016 // scroll to first matching element based on key pres..
15017 if (e.isSpecialKey()) {
15020 var k = String.fromCharCode(e.getKey()).toUpperCase();
15023 var csel = this.view.getSelectedNodes();
15024 var cselitem = false;
15026 var ix = this.view.indexOf(csel[0]);
15027 cselitem = this.store.getAt(ix);
15028 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15034 this.store.each(function(v) {
15036 // start at existing selection.
15037 if (cselitem.id == v.id) {
15043 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15044 match = this.store.indexOf(v);
15050 if (match === false) {
15051 return true; // no more action?
15054 this.view.select(match);
15055 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15056 sn.scrollIntoView(sn.dom.parentNode, false);
15059 onViewScroll : function(e, t){
15061 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){
15065 this.hasQuery = true;
15067 this.loading = this.list.select('.loading', true).first();
15069 if(this.loading === null){
15070 this.list.createChild({
15072 cls: 'loading roo-select2-more-results roo-select2-active',
15073 html: 'Loading more results...'
15076 this.loading = this.list.select('.loading', true).first();
15078 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15080 this.loading.hide();
15083 this.loading.show();
15088 this.loadNext = true;
15090 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15095 addItem : function(o)
15097 var dv = ''; // display value
15099 if (this.displayField) {
15100 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15102 // this is an error condition!!!
15103 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15110 var choice = this.choices.createChild({
15112 cls: 'roo-select2-search-choice',
15121 cls: 'roo-select2-search-choice-close fa fa-times',
15126 }, this.searchField);
15128 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15130 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15138 this.inputEl().dom.value = '';
15143 onRemoveItem : function(e, _self, o)
15145 e.preventDefault();
15147 this.lastItem = Roo.apply([], this.item);
15149 var index = this.item.indexOf(o.data) * 1;
15152 Roo.log('not this item?!');
15156 this.item.splice(index, 1);
15161 this.fireEvent('remove', this, e);
15167 syncValue : function()
15169 if(!this.item.length){
15176 Roo.each(this.item, function(i){
15177 if(_this.valueField){
15178 value.push(i[_this.valueField]);
15185 this.value = value.join(',');
15187 if(this.hiddenField){
15188 this.hiddenField.dom.value = this.value;
15191 this.store.fireEvent("datachanged", this.store);
15196 clearItem : function()
15198 if(!this.multiple){
15204 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15212 if(this.tickable && !Roo.isTouch){
15213 this.view.refresh();
15217 inputEl: function ()
15219 if(Roo.isIOS && this.useNativeIOS){
15220 return this.el.select('select.roo-ios-select', true).first();
15223 if(Roo.isTouch && this.mobileTouchView){
15224 return this.el.select('input.form-control',true).first();
15228 return this.searchField;
15231 return this.el.select('input.form-control',true).first();
15234 onTickableFooterButtonClick : function(e, btn, el)
15236 e.preventDefault();
15238 this.lastItem = Roo.apply([], this.item);
15240 if(btn && btn.name == 'cancel'){
15241 this.tickItems = Roo.apply([], this.item);
15250 Roo.each(this.tickItems, function(o){
15258 validate : function()
15260 if(this.getVisibilityEl().hasClass('hidden')){
15264 var v = this.getRawValue();
15267 v = this.getValue();
15270 if(this.disabled || this.allowBlank || v.length){
15275 this.markInvalid();
15279 tickableInputEl : function()
15281 if(!this.tickable || !this.editable){
15282 return this.inputEl();
15285 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15289 getAutoCreateTouchView : function()
15294 cls: 'form-group' //input-group
15300 type : this.inputType,
15301 cls : 'form-control x-combo-noedit',
15302 autocomplete: 'new-password',
15303 placeholder : this.placeholder || '',
15308 input.name = this.name;
15312 input.cls += ' input-' + this.size;
15315 if (this.disabled) {
15316 input.disabled = true;
15327 inputblock.cls += ' input-group';
15329 inputblock.cn.unshift({
15331 cls : 'input-group-addon input-group-prepend input-group-text',
15336 if(this.removable && !this.multiple){
15337 inputblock.cls += ' roo-removable';
15339 inputblock.cn.push({
15342 cls : 'roo-combo-removable-btn close'
15346 if(this.hasFeedback && !this.allowBlank){
15348 inputblock.cls += ' has-feedback';
15350 inputblock.cn.push({
15352 cls: 'glyphicon form-control-feedback'
15359 inputblock.cls += (this.before) ? '' : ' input-group';
15361 inputblock.cn.push({
15363 cls : 'input-group-addon input-group-append input-group-text',
15369 var ibwrap = inputblock;
15374 cls: 'roo-select2-choices',
15378 cls: 'roo-select2-search-field',
15391 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15396 cls: 'form-hidden-field'
15402 if(!this.multiple && this.showToggleBtn){
15408 if (this.caret != false) {
15411 cls: 'fa fa-' + this.caret
15418 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15420 Roo.bootstrap.version == 3 ? caret : '',
15423 cls: 'combobox-clear',
15437 combobox.cls += ' roo-select2-container-multi';
15440 var align = this.labelAlign || this.parentLabelAlign();
15442 if (align ==='left' && this.fieldLabel.length) {
15447 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15448 tooltip : 'This field is required'
15452 cls : 'control-label col-form-label',
15453 html : this.fieldLabel
15464 var labelCfg = cfg.cn[1];
15465 var contentCfg = cfg.cn[2];
15468 if(this.indicatorpos == 'right'){
15473 cls : 'control-label col-form-label',
15477 html : this.fieldLabel
15481 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15482 tooltip : 'This field is required'
15495 labelCfg = cfg.cn[0];
15496 contentCfg = cfg.cn[1];
15501 if(this.labelWidth > 12){
15502 labelCfg.style = "width: " + this.labelWidth + 'px';
15505 if(this.labelWidth < 13 && this.labelmd == 0){
15506 this.labelmd = this.labelWidth;
15509 if(this.labellg > 0){
15510 labelCfg.cls += ' col-lg-' + this.labellg;
15511 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15514 if(this.labelmd > 0){
15515 labelCfg.cls += ' col-md-' + this.labelmd;
15516 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15519 if(this.labelsm > 0){
15520 labelCfg.cls += ' col-sm-' + this.labelsm;
15521 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15524 if(this.labelxs > 0){
15525 labelCfg.cls += ' col-xs-' + this.labelxs;
15526 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15530 } else if ( this.fieldLabel.length) {
15534 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15535 tooltip : 'This field is required'
15539 cls : 'control-label',
15540 html : this.fieldLabel
15551 if(this.indicatorpos == 'right'){
15555 cls : 'control-label',
15556 html : this.fieldLabel,
15560 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15561 tooltip : 'This field is required'
15578 var settings = this;
15580 ['xs','sm','md','lg'].map(function(size){
15581 if (settings[size]) {
15582 cfg.cls += ' col-' + size + '-' + settings[size];
15589 initTouchView : function()
15591 this.renderTouchView();
15593 this.touchViewEl.on('scroll', function(){
15594 this.el.dom.scrollTop = 0;
15597 this.originalValue = this.getValue();
15599 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15601 this.inputEl().on("click", this.showTouchView, this);
15602 if (this.triggerEl) {
15603 this.triggerEl.on("click", this.showTouchView, this);
15607 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15608 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15610 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15612 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15613 this.store.on('load', this.onTouchViewLoad, this);
15614 this.store.on('loadexception', this.onTouchViewLoadException, this);
15616 if(this.hiddenName){
15618 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15620 this.hiddenField.dom.value =
15621 this.hiddenValue !== undefined ? this.hiddenValue :
15622 this.value !== undefined ? this.value : '';
15624 this.el.dom.removeAttribute('name');
15625 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15629 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15630 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15633 if(this.removable && !this.multiple){
15634 var close = this.closeTriggerEl();
15636 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15637 close.on('click', this.removeBtnClick, this, close);
15641 * fix the bug in Safari iOS8
15643 this.inputEl().on("focus", function(e){
15644 document.activeElement.blur();
15647 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15654 renderTouchView : function()
15656 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15657 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15659 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15660 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15662 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15663 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15664 this.touchViewBodyEl.setStyle('overflow', 'auto');
15666 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15667 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15669 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15670 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15674 showTouchView : function()
15680 this.touchViewHeaderEl.hide();
15682 if(this.modalTitle.length){
15683 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15684 this.touchViewHeaderEl.show();
15687 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15688 this.touchViewEl.show();
15690 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15692 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15693 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15695 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15697 if(this.modalTitle.length){
15698 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15701 this.touchViewBodyEl.setHeight(bodyHeight);
15705 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15707 this.touchViewEl.addClass('in');
15710 if(this._touchViewMask){
15711 Roo.get(document.body).addClass("x-body-masked");
15712 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15713 this._touchViewMask.setStyle('z-index', 10000);
15714 this._touchViewMask.addClass('show');
15717 this.doTouchViewQuery();
15721 hideTouchView : function()
15723 this.touchViewEl.removeClass('in');
15727 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15729 this.touchViewEl.setStyle('display', 'none');
15732 if(this._touchViewMask){
15733 this._touchViewMask.removeClass('show');
15734 Roo.get(document.body).removeClass("x-body-masked");
15738 setTouchViewValue : function()
15745 Roo.each(this.tickItems, function(o){
15750 this.hideTouchView();
15753 doTouchViewQuery : function()
15762 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15766 if(!this.alwaysQuery || this.mode == 'local'){
15767 this.onTouchViewLoad();
15774 onTouchViewBeforeLoad : function(combo,opts)
15780 onTouchViewLoad : function()
15782 if(this.store.getCount() < 1){
15783 this.onTouchViewEmptyResults();
15787 this.clearTouchView();
15789 var rawValue = this.getRawValue();
15791 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15793 this.tickItems = [];
15795 this.store.data.each(function(d, rowIndex){
15796 var row = this.touchViewListGroup.createChild(template);
15798 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15799 row.addClass(d.data.cls);
15802 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15805 html : d.data[this.displayField]
15808 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15809 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15812 row.removeClass('selected');
15813 if(!this.multiple && this.valueField &&
15814 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15817 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15818 row.addClass('selected');
15821 if(this.multiple && this.valueField &&
15822 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15826 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15827 this.tickItems.push(d.data);
15830 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15834 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15836 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15838 if(this.modalTitle.length){
15839 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15842 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15844 if(this.mobile_restrict_height && listHeight < bodyHeight){
15845 this.touchViewBodyEl.setHeight(listHeight);
15850 if(firstChecked && listHeight > bodyHeight){
15851 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15856 onTouchViewLoadException : function()
15858 this.hideTouchView();
15861 onTouchViewEmptyResults : function()
15863 this.clearTouchView();
15865 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15867 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15871 clearTouchView : function()
15873 this.touchViewListGroup.dom.innerHTML = '';
15876 onTouchViewClick : function(e, el, o)
15878 e.preventDefault();
15881 var rowIndex = o.rowIndex;
15883 var r = this.store.getAt(rowIndex);
15885 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15887 if(!this.multiple){
15888 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15889 c.dom.removeAttribute('checked');
15892 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15894 this.setFromData(r.data);
15896 var close = this.closeTriggerEl();
15902 this.hideTouchView();
15904 this.fireEvent('select', this, r, rowIndex);
15909 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15910 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15911 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15915 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15916 this.addItem(r.data);
15917 this.tickItems.push(r.data);
15921 getAutoCreateNativeIOS : function()
15924 cls: 'form-group' //input-group,
15929 cls : 'roo-ios-select'
15933 combobox.name = this.name;
15936 if (this.disabled) {
15937 combobox.disabled = true;
15940 var settings = this;
15942 ['xs','sm','md','lg'].map(function(size){
15943 if (settings[size]) {
15944 cfg.cls += ' col-' + size + '-' + settings[size];
15954 initIOSView : function()
15956 this.store.on('load', this.onIOSViewLoad, this);
15961 onIOSViewLoad : function()
15963 if(this.store.getCount() < 1){
15967 this.clearIOSView();
15969 if(this.allowBlank) {
15971 var default_text = '-- SELECT --';
15973 if(this.placeholder.length){
15974 default_text = this.placeholder;
15977 if(this.emptyTitle.length){
15978 default_text += ' - ' + this.emptyTitle + ' -';
15981 var opt = this.inputEl().createChild({
15984 html : default_text
15988 o[this.valueField] = 0;
15989 o[this.displayField] = default_text;
15991 this.ios_options.push({
15998 this.store.data.each(function(d, rowIndex){
16002 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16003 html = d.data[this.displayField];
16008 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16009 value = d.data[this.valueField];
16018 if(this.value == d.data[this.valueField]){
16019 option['selected'] = true;
16022 var opt = this.inputEl().createChild(option);
16024 this.ios_options.push({
16031 this.inputEl().on('change', function(){
16032 this.fireEvent('select', this);
16037 clearIOSView: function()
16039 this.inputEl().dom.innerHTML = '';
16041 this.ios_options = [];
16044 setIOSValue: function(v)
16048 if(!this.ios_options){
16052 Roo.each(this.ios_options, function(opts){
16054 opts.el.dom.removeAttribute('selected');
16056 if(opts.data[this.valueField] != v){
16060 opts.el.dom.setAttribute('selected', true);
16066 * @cfg {Boolean} grow
16070 * @cfg {Number} growMin
16074 * @cfg {Number} growMax
16083 Roo.apply(Roo.bootstrap.ComboBox, {
16087 cls: 'modal-header',
16109 cls: 'list-group-item',
16113 cls: 'roo-combobox-list-group-item-value'
16117 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16131 listItemCheckbox : {
16133 cls: 'list-group-item',
16137 cls: 'roo-combobox-list-group-item-value'
16141 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16157 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16162 cls: 'modal-footer',
16170 cls: 'col-xs-6 text-left',
16173 cls: 'btn btn-danger roo-touch-view-cancel',
16179 cls: 'col-xs-6 text-right',
16182 cls: 'btn btn-success roo-touch-view-ok',
16193 Roo.apply(Roo.bootstrap.ComboBox, {
16195 touchViewTemplate : {
16197 cls: 'modal fade roo-combobox-touch-view',
16201 cls: 'modal-dialog',
16202 style : 'position:fixed', // we have to fix position....
16206 cls: 'modal-content',
16208 Roo.bootstrap.ComboBox.header,
16209 Roo.bootstrap.ComboBox.body,
16210 Roo.bootstrap.ComboBox.footer
16219 * Ext JS Library 1.1.1
16220 * Copyright(c) 2006-2007, Ext JS, LLC.
16222 * Originally Released Under LGPL - original licence link has changed is not relivant.
16225 * <script type="text/javascript">
16230 * @extends Roo.util.Observable
16231 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16232 * This class also supports single and multi selection modes. <br>
16233 * Create a data model bound view:
16235 var store = new Roo.data.Store(...);
16237 var view = new Roo.View({
16239 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16241 singleSelect: true,
16242 selectedClass: "ydataview-selected",
16246 // listen for node click?
16247 view.on("click", function(vw, index, node, e){
16248 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16252 dataModel.load("foobar.xml");
16254 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16256 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16257 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16259 * Note: old style constructor is still suported (container, template, config)
16262 * Create a new View
16263 * @param {Object} config The config object
16266 Roo.View = function(config, depreciated_tpl, depreciated_config){
16268 this.parent = false;
16270 if (typeof(depreciated_tpl) == 'undefined') {
16271 // new way.. - universal constructor.
16272 Roo.apply(this, config);
16273 this.el = Roo.get(this.el);
16276 this.el = Roo.get(config);
16277 this.tpl = depreciated_tpl;
16278 Roo.apply(this, depreciated_config);
16280 this.wrapEl = this.el.wrap().wrap();
16281 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16284 if(typeof(this.tpl) == "string"){
16285 this.tpl = new Roo.Template(this.tpl);
16287 // support xtype ctors..
16288 this.tpl = new Roo.factory(this.tpl, Roo);
16292 this.tpl.compile();
16297 * @event beforeclick
16298 * Fires before a click is processed. Returns false to cancel the default action.
16299 * @param {Roo.View} this
16300 * @param {Number} index The index of the target node
16301 * @param {HTMLElement} node The target node
16302 * @param {Roo.EventObject} e The raw event object
16304 "beforeclick" : true,
16307 * Fires when a template node is clicked.
16308 * @param {Roo.View} this
16309 * @param {Number} index The index of the target node
16310 * @param {HTMLElement} node The target node
16311 * @param {Roo.EventObject} e The raw event object
16316 * Fires when a template node is double clicked.
16317 * @param {Roo.View} this
16318 * @param {Number} index The index of the target node
16319 * @param {HTMLElement} node The target node
16320 * @param {Roo.EventObject} e The raw event object
16324 * @event contextmenu
16325 * Fires when a template node is right clicked.
16326 * @param {Roo.View} this
16327 * @param {Number} index The index of the target node
16328 * @param {HTMLElement} node The target node
16329 * @param {Roo.EventObject} e The raw event object
16331 "contextmenu" : true,
16333 * @event selectionchange
16334 * Fires when the selected nodes change.
16335 * @param {Roo.View} this
16336 * @param {Array} selections Array of the selected nodes
16338 "selectionchange" : true,
16341 * @event beforeselect
16342 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16343 * @param {Roo.View} this
16344 * @param {HTMLElement} node The node to be selected
16345 * @param {Array} selections Array of currently selected nodes
16347 "beforeselect" : true,
16349 * @event preparedata
16350 * Fires on every row to render, to allow you to change the data.
16351 * @param {Roo.View} this
16352 * @param {Object} data to be rendered (change this)
16354 "preparedata" : true
16362 "click": this.onClick,
16363 "dblclick": this.onDblClick,
16364 "contextmenu": this.onContextMenu,
16368 this.selections = [];
16370 this.cmp = new Roo.CompositeElementLite([]);
16372 this.store = Roo.factory(this.store, Roo.data);
16373 this.setStore(this.store, true);
16376 if ( this.footer && this.footer.xtype) {
16378 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16380 this.footer.dataSource = this.store;
16381 this.footer.container = fctr;
16382 this.footer = Roo.factory(this.footer, Roo);
16383 fctr.insertFirst(this.el);
16385 // this is a bit insane - as the paging toolbar seems to detach the el..
16386 // dom.parentNode.parentNode.parentNode
16387 // they get detached?
16391 Roo.View.superclass.constructor.call(this);
16396 Roo.extend(Roo.View, Roo.util.Observable, {
16399 * @cfg {Roo.data.Store} store Data store to load data from.
16404 * @cfg {String|Roo.Element} el The container element.
16409 * @cfg {String|Roo.Template} tpl The template used by this View
16413 * @cfg {String} dataName the named area of the template to use as the data area
16414 * Works with domtemplates roo-name="name"
16418 * @cfg {String} selectedClass The css class to add to selected nodes
16420 selectedClass : "x-view-selected",
16422 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16427 * @cfg {String} text to display on mask (default Loading)
16431 * @cfg {Boolean} multiSelect Allow multiple selection
16433 multiSelect : false,
16435 * @cfg {Boolean} singleSelect Allow single selection
16437 singleSelect: false,
16440 * @cfg {Boolean} toggleSelect - selecting
16442 toggleSelect : false,
16445 * @cfg {Boolean} tickable - selecting
16450 * Returns the element this view is bound to.
16451 * @return {Roo.Element}
16453 getEl : function(){
16454 return this.wrapEl;
16460 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16462 refresh : function(){
16463 //Roo.log('refresh');
16466 // if we are using something like 'domtemplate', then
16467 // the what gets used is:
16468 // t.applySubtemplate(NAME, data, wrapping data..)
16469 // the outer template then get' applied with
16470 // the store 'extra data'
16471 // and the body get's added to the
16472 // roo-name="data" node?
16473 // <span class='roo-tpl-{name}'></span> ?????
16477 this.clearSelections();
16478 this.el.update("");
16480 var records = this.store.getRange();
16481 if(records.length < 1) {
16483 // is this valid?? = should it render a template??
16485 this.el.update(this.emptyText);
16489 if (this.dataName) {
16490 this.el.update(t.apply(this.store.meta)); //????
16491 el = this.el.child('.roo-tpl-' + this.dataName);
16494 for(var i = 0, len = records.length; i < len; i++){
16495 var data = this.prepareData(records[i].data, i, records[i]);
16496 this.fireEvent("preparedata", this, data, i, records[i]);
16498 var d = Roo.apply({}, data);
16501 Roo.apply(d, {'roo-id' : Roo.id()});
16505 Roo.each(this.parent.item, function(item){
16506 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16509 Roo.apply(d, {'roo-data-checked' : 'checked'});
16513 html[html.length] = Roo.util.Format.trim(
16515 t.applySubtemplate(this.dataName, d, this.store.meta) :
16522 el.update(html.join(""));
16523 this.nodes = el.dom.childNodes;
16524 this.updateIndexes(0);
16529 * Function to override to reformat the data that is sent to
16530 * the template for each node.
16531 * DEPRICATED - use the preparedata event handler.
16532 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16533 * a JSON object for an UpdateManager bound view).
16535 prepareData : function(data, index, record)
16537 this.fireEvent("preparedata", this, data, index, record);
16541 onUpdate : function(ds, record){
16542 // Roo.log('on update');
16543 this.clearSelections();
16544 var index = this.store.indexOf(record);
16545 var n = this.nodes[index];
16546 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16547 n.parentNode.removeChild(n);
16548 this.updateIndexes(index, index);
16554 onAdd : function(ds, records, index)
16556 //Roo.log(['on Add', ds, records, index] );
16557 this.clearSelections();
16558 if(this.nodes.length == 0){
16562 var n = this.nodes[index];
16563 for(var i = 0, len = records.length; i < len; i++){
16564 var d = this.prepareData(records[i].data, i, records[i]);
16566 this.tpl.insertBefore(n, d);
16569 this.tpl.append(this.el, d);
16572 this.updateIndexes(index);
16575 onRemove : function(ds, record, index){
16576 // Roo.log('onRemove');
16577 this.clearSelections();
16578 var el = this.dataName ?
16579 this.el.child('.roo-tpl-' + this.dataName) :
16582 el.dom.removeChild(this.nodes[index]);
16583 this.updateIndexes(index);
16587 * Refresh an individual node.
16588 * @param {Number} index
16590 refreshNode : function(index){
16591 this.onUpdate(this.store, this.store.getAt(index));
16594 updateIndexes : function(startIndex, endIndex){
16595 var ns = this.nodes;
16596 startIndex = startIndex || 0;
16597 endIndex = endIndex || ns.length - 1;
16598 for(var i = startIndex; i <= endIndex; i++){
16599 ns[i].nodeIndex = i;
16604 * Changes the data store this view uses and refresh the view.
16605 * @param {Store} store
16607 setStore : function(store, initial){
16608 if(!initial && this.store){
16609 this.store.un("datachanged", this.refresh);
16610 this.store.un("add", this.onAdd);
16611 this.store.un("remove", this.onRemove);
16612 this.store.un("update", this.onUpdate);
16613 this.store.un("clear", this.refresh);
16614 this.store.un("beforeload", this.onBeforeLoad);
16615 this.store.un("load", this.onLoad);
16616 this.store.un("loadexception", this.onLoad);
16620 store.on("datachanged", this.refresh, this);
16621 store.on("add", this.onAdd, this);
16622 store.on("remove", this.onRemove, this);
16623 store.on("update", this.onUpdate, this);
16624 store.on("clear", this.refresh, this);
16625 store.on("beforeload", this.onBeforeLoad, this);
16626 store.on("load", this.onLoad, this);
16627 store.on("loadexception", this.onLoad, this);
16635 * onbeforeLoad - masks the loading area.
16638 onBeforeLoad : function(store,opts)
16640 //Roo.log('onBeforeLoad');
16642 this.el.update("");
16644 this.el.mask(this.mask ? this.mask : "Loading" );
16646 onLoad : function ()
16653 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16654 * @param {HTMLElement} node
16655 * @return {HTMLElement} The template node
16657 findItemFromChild : function(node){
16658 var el = this.dataName ?
16659 this.el.child('.roo-tpl-' + this.dataName,true) :
16662 if(!node || node.parentNode == el){
16665 var p = node.parentNode;
16666 while(p && p != el){
16667 if(p.parentNode == el){
16676 onClick : function(e){
16677 var item = this.findItemFromChild(e.getTarget());
16679 var index = this.indexOf(item);
16680 if(this.onItemClick(item, index, e) !== false){
16681 this.fireEvent("click", this, index, item, e);
16684 this.clearSelections();
16689 onContextMenu : function(e){
16690 var item = this.findItemFromChild(e.getTarget());
16692 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16697 onDblClick : function(e){
16698 var item = this.findItemFromChild(e.getTarget());
16700 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16704 onItemClick : function(item, index, e)
16706 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16709 if (this.toggleSelect) {
16710 var m = this.isSelected(item) ? 'unselect' : 'select';
16713 _t[m](item, true, false);
16716 if(this.multiSelect || this.singleSelect){
16717 if(this.multiSelect && e.shiftKey && this.lastSelection){
16718 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16720 this.select(item, this.multiSelect && e.ctrlKey);
16721 this.lastSelection = item;
16724 if(!this.tickable){
16725 e.preventDefault();
16733 * Get the number of selected nodes.
16736 getSelectionCount : function(){
16737 return this.selections.length;
16741 * Get the currently selected nodes.
16742 * @return {Array} An array of HTMLElements
16744 getSelectedNodes : function(){
16745 return this.selections;
16749 * Get the indexes of the selected nodes.
16752 getSelectedIndexes : function(){
16753 var indexes = [], s = this.selections;
16754 for(var i = 0, len = s.length; i < len; i++){
16755 indexes.push(s[i].nodeIndex);
16761 * Clear all selections
16762 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16764 clearSelections : function(suppressEvent){
16765 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16766 this.cmp.elements = this.selections;
16767 this.cmp.removeClass(this.selectedClass);
16768 this.selections = [];
16769 if(!suppressEvent){
16770 this.fireEvent("selectionchange", this, this.selections);
16776 * Returns true if the passed node is selected
16777 * @param {HTMLElement/Number} node The node or node index
16778 * @return {Boolean}
16780 isSelected : function(node){
16781 var s = this.selections;
16785 node = this.getNode(node);
16786 return s.indexOf(node) !== -1;
16791 * @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
16792 * @param {Boolean} keepExisting (optional) true to keep existing selections
16793 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16795 select : function(nodeInfo, keepExisting, suppressEvent){
16796 if(nodeInfo instanceof Array){
16798 this.clearSelections(true);
16800 for(var i = 0, len = nodeInfo.length; i < len; i++){
16801 this.select(nodeInfo[i], true, true);
16805 var node = this.getNode(nodeInfo);
16806 if(!node || this.isSelected(node)){
16807 return; // already selected.
16810 this.clearSelections(true);
16813 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16814 Roo.fly(node).addClass(this.selectedClass);
16815 this.selections.push(node);
16816 if(!suppressEvent){
16817 this.fireEvent("selectionchange", this, this.selections);
16825 * @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
16826 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16827 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16829 unselect : function(nodeInfo, keepExisting, suppressEvent)
16831 if(nodeInfo instanceof Array){
16832 Roo.each(this.selections, function(s) {
16833 this.unselect(s, nodeInfo);
16837 var node = this.getNode(nodeInfo);
16838 if(!node || !this.isSelected(node)){
16839 //Roo.log("not selected");
16840 return; // not selected.
16844 Roo.each(this.selections, function(s) {
16846 Roo.fly(node).removeClass(this.selectedClass);
16853 this.selections= ns;
16854 this.fireEvent("selectionchange", this, this.selections);
16858 * Gets a template node.
16859 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16860 * @return {HTMLElement} The node or null if it wasn't found
16862 getNode : function(nodeInfo){
16863 if(typeof nodeInfo == "string"){
16864 return document.getElementById(nodeInfo);
16865 }else if(typeof nodeInfo == "number"){
16866 return this.nodes[nodeInfo];
16872 * Gets a range template nodes.
16873 * @param {Number} startIndex
16874 * @param {Number} endIndex
16875 * @return {Array} An array of nodes
16877 getNodes : function(start, end){
16878 var ns = this.nodes;
16879 start = start || 0;
16880 end = typeof end == "undefined" ? ns.length - 1 : end;
16883 for(var i = start; i <= end; i++){
16887 for(var i = start; i >= end; i--){
16895 * Finds the index of the passed node
16896 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16897 * @return {Number} The index of the node or -1
16899 indexOf : function(node){
16900 node = this.getNode(node);
16901 if(typeof node.nodeIndex == "number"){
16902 return node.nodeIndex;
16904 var ns = this.nodes;
16905 for(var i = 0, len = ns.length; i < len; i++){
16916 * based on jquery fullcalendar
16920 Roo.bootstrap = Roo.bootstrap || {};
16922 * @class Roo.bootstrap.Calendar
16923 * @extends Roo.bootstrap.Component
16924 * Bootstrap Calendar class
16925 * @cfg {Boolean} loadMask (true|false) default false
16926 * @cfg {Object} header generate the user specific header of the calendar, default false
16929 * Create a new Container
16930 * @param {Object} config The config object
16935 Roo.bootstrap.Calendar = function(config){
16936 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16940 * Fires when a date is selected
16941 * @param {DatePicker} this
16942 * @param {Date} date The selected date
16946 * @event monthchange
16947 * Fires when the displayed month changes
16948 * @param {DatePicker} this
16949 * @param {Date} date The selected month
16951 'monthchange': true,
16953 * @event evententer
16954 * Fires when mouse over an event
16955 * @param {Calendar} this
16956 * @param {event} Event
16958 'evententer': true,
16960 * @event eventleave
16961 * Fires when the mouse leaves an
16962 * @param {Calendar} this
16965 'eventleave': true,
16967 * @event eventclick
16968 * Fires when the mouse click an
16969 * @param {Calendar} this
16978 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16981 * @cfg {Number} startDay
16982 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16990 getAutoCreate : function(){
16993 var fc_button = function(name, corner, style, content ) {
16994 return Roo.apply({},{
16996 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16998 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
17001 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17012 style : 'width:100%',
17019 cls : 'fc-header-left',
17021 fc_button('prev', 'left', 'arrow', '‹' ),
17022 fc_button('next', 'right', 'arrow', '›' ),
17023 { tag: 'span', cls: 'fc-header-space' },
17024 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17032 cls : 'fc-header-center',
17036 cls: 'fc-header-title',
17039 html : 'month / year'
17047 cls : 'fc-header-right',
17049 /* fc_button('month', 'left', '', 'month' ),
17050 fc_button('week', '', '', 'week' ),
17051 fc_button('day', 'right', '', 'day' )
17063 header = this.header;
17066 var cal_heads = function() {
17068 // fixme - handle this.
17070 for (var i =0; i < Date.dayNames.length; i++) {
17071 var d = Date.dayNames[i];
17074 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17075 html : d.substring(0,3)
17079 ret[0].cls += ' fc-first';
17080 ret[6].cls += ' fc-last';
17083 var cal_cell = function(n) {
17086 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17091 cls: 'fc-day-number',
17095 cls: 'fc-day-content',
17099 style: 'position: relative;' // height: 17px;
17111 var cal_rows = function() {
17114 for (var r = 0; r < 6; r++) {
17121 for (var i =0; i < Date.dayNames.length; i++) {
17122 var d = Date.dayNames[i];
17123 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17126 row.cn[0].cls+=' fc-first';
17127 row.cn[0].cn[0].style = 'min-height:90px';
17128 row.cn[6].cls+=' fc-last';
17132 ret[0].cls += ' fc-first';
17133 ret[4].cls += ' fc-prev-last';
17134 ret[5].cls += ' fc-last';
17141 cls: 'fc-border-separate',
17142 style : 'width:100%',
17150 cls : 'fc-first fc-last',
17168 cls : 'fc-content',
17169 style : "position: relative;",
17172 cls : 'fc-view fc-view-month fc-grid',
17173 style : 'position: relative',
17174 unselectable : 'on',
17177 cls : 'fc-event-container',
17178 style : 'position:absolute;z-index:8;top:0;left:0;'
17196 initEvents : function()
17199 throw "can not find store for calendar";
17205 style: "text-align:center",
17209 style: "background-color:white;width:50%;margin:250 auto",
17213 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17224 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17226 var size = this.el.select('.fc-content', true).first().getSize();
17227 this.maskEl.setSize(size.width, size.height);
17228 this.maskEl.enableDisplayMode("block");
17229 if(!this.loadMask){
17230 this.maskEl.hide();
17233 this.store = Roo.factory(this.store, Roo.data);
17234 this.store.on('load', this.onLoad, this);
17235 this.store.on('beforeload', this.onBeforeLoad, this);
17239 this.cells = this.el.select('.fc-day',true);
17240 //Roo.log(this.cells);
17241 this.textNodes = this.el.query('.fc-day-number');
17242 this.cells.addClassOnOver('fc-state-hover');
17244 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17245 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17246 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17247 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17249 this.on('monthchange', this.onMonthChange, this);
17251 this.update(new Date().clearTime());
17254 resize : function() {
17255 var sz = this.el.getSize();
17257 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17258 this.el.select('.fc-day-content div',true).setHeight(34);
17263 showPrevMonth : function(e){
17264 this.update(this.activeDate.add("mo", -1));
17266 showToday : function(e){
17267 this.update(new Date().clearTime());
17270 showNextMonth : function(e){
17271 this.update(this.activeDate.add("mo", 1));
17275 showPrevYear : function(){
17276 this.update(this.activeDate.add("y", -1));
17280 showNextYear : function(){
17281 this.update(this.activeDate.add("y", 1));
17286 update : function(date)
17288 var vd = this.activeDate;
17289 this.activeDate = date;
17290 // if(vd && this.el){
17291 // var t = date.getTime();
17292 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17293 // Roo.log('using add remove');
17295 // this.fireEvent('monthchange', this, date);
17297 // this.cells.removeClass("fc-state-highlight");
17298 // this.cells.each(function(c){
17299 // if(c.dateValue == t){
17300 // c.addClass("fc-state-highlight");
17301 // setTimeout(function(){
17302 // try{c.dom.firstChild.focus();}catch(e){}
17312 var days = date.getDaysInMonth();
17314 var firstOfMonth = date.getFirstDateOfMonth();
17315 var startingPos = firstOfMonth.getDay()-this.startDay;
17317 if(startingPos < this.startDay){
17321 var pm = date.add(Date.MONTH, -1);
17322 var prevStart = pm.getDaysInMonth()-startingPos;
17324 this.cells = this.el.select('.fc-day',true);
17325 this.textNodes = this.el.query('.fc-day-number');
17326 this.cells.addClassOnOver('fc-state-hover');
17328 var cells = this.cells.elements;
17329 var textEls = this.textNodes;
17331 Roo.each(cells, function(cell){
17332 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17335 days += startingPos;
17337 // convert everything to numbers so it's fast
17338 var day = 86400000;
17339 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17342 //Roo.log(prevStart);
17344 var today = new Date().clearTime().getTime();
17345 var sel = date.clearTime().getTime();
17346 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17347 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17348 var ddMatch = this.disabledDatesRE;
17349 var ddText = this.disabledDatesText;
17350 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17351 var ddaysText = this.disabledDaysText;
17352 var format = this.format;
17354 var setCellClass = function(cal, cell){
17358 //Roo.log('set Cell Class');
17360 var t = d.getTime();
17364 cell.dateValue = t;
17366 cell.className += " fc-today";
17367 cell.className += " fc-state-highlight";
17368 cell.title = cal.todayText;
17371 // disable highlight in other month..
17372 //cell.className += " fc-state-highlight";
17377 cell.className = " fc-state-disabled";
17378 cell.title = cal.minText;
17382 cell.className = " fc-state-disabled";
17383 cell.title = cal.maxText;
17387 if(ddays.indexOf(d.getDay()) != -1){
17388 cell.title = ddaysText;
17389 cell.className = " fc-state-disabled";
17392 if(ddMatch && format){
17393 var fvalue = d.dateFormat(format);
17394 if(ddMatch.test(fvalue)){
17395 cell.title = ddText.replace("%0", fvalue);
17396 cell.className = " fc-state-disabled";
17400 if (!cell.initialClassName) {
17401 cell.initialClassName = cell.dom.className;
17404 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17409 for(; i < startingPos; i++) {
17410 textEls[i].innerHTML = (++prevStart);
17411 d.setDate(d.getDate()+1);
17413 cells[i].className = "fc-past fc-other-month";
17414 setCellClass(this, cells[i]);
17419 for(; i < days; i++){
17420 intDay = i - startingPos + 1;
17421 textEls[i].innerHTML = (intDay);
17422 d.setDate(d.getDate()+1);
17424 cells[i].className = ''; // "x-date-active";
17425 setCellClass(this, cells[i]);
17429 for(; i < 42; i++) {
17430 textEls[i].innerHTML = (++extraDays);
17431 d.setDate(d.getDate()+1);
17433 cells[i].className = "fc-future fc-other-month";
17434 setCellClass(this, cells[i]);
17437 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17439 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17441 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17442 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17444 if(totalRows != 6){
17445 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17446 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17449 this.fireEvent('monthchange', this, date);
17453 if(!this.internalRender){
17454 var main = this.el.dom.firstChild;
17455 var w = main.offsetWidth;
17456 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17457 Roo.fly(main).setWidth(w);
17458 this.internalRender = true;
17459 // opera does not respect the auto grow header center column
17460 // then, after it gets a width opera refuses to recalculate
17461 // without a second pass
17462 if(Roo.isOpera && !this.secondPass){
17463 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17464 this.secondPass = true;
17465 this.update.defer(10, this, [date]);
17472 findCell : function(dt) {
17473 dt = dt.clearTime().getTime();
17475 this.cells.each(function(c){
17476 //Roo.log("check " +c.dateValue + '?=' + dt);
17477 if(c.dateValue == dt){
17487 findCells : function(ev) {
17488 var s = ev.start.clone().clearTime().getTime();
17490 var e= ev.end.clone().clearTime().getTime();
17493 this.cells.each(function(c){
17494 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17496 if(c.dateValue > e){
17499 if(c.dateValue < s){
17508 // findBestRow: function(cells)
17512 // for (var i =0 ; i < cells.length;i++) {
17513 // ret = Math.max(cells[i].rows || 0,ret);
17520 addItem : function(ev)
17522 // look for vertical location slot in
17523 var cells = this.findCells(ev);
17525 // ev.row = this.findBestRow(cells);
17527 // work out the location.
17531 for(var i =0; i < cells.length; i++) {
17533 cells[i].row = cells[0].row;
17536 cells[i].row = cells[i].row + 1;
17546 if (crow.start.getY() == cells[i].getY()) {
17548 crow.end = cells[i];
17565 cells[0].events.push(ev);
17567 this.calevents.push(ev);
17570 clearEvents: function() {
17572 if(!this.calevents){
17576 Roo.each(this.cells.elements, function(c){
17582 Roo.each(this.calevents, function(e) {
17583 Roo.each(e.els, function(el) {
17584 el.un('mouseenter' ,this.onEventEnter, this);
17585 el.un('mouseleave' ,this.onEventLeave, this);
17590 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17596 renderEvents: function()
17600 this.cells.each(function(c) {
17609 if(c.row != c.events.length){
17610 r = 4 - (4 - (c.row - c.events.length));
17613 c.events = ev.slice(0, r);
17614 c.more = ev.slice(r);
17616 if(c.more.length && c.more.length == 1){
17617 c.events.push(c.more.pop());
17620 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17624 this.cells.each(function(c) {
17626 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17629 for (var e = 0; e < c.events.length; e++){
17630 var ev = c.events[e];
17631 var rows = ev.rows;
17633 for(var i = 0; i < rows.length; i++) {
17635 // how many rows should it span..
17638 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17639 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17641 unselectable : "on",
17644 cls: 'fc-event-inner',
17648 // cls: 'fc-event-time',
17649 // html : cells.length > 1 ? '' : ev.time
17653 cls: 'fc-event-title',
17654 html : String.format('{0}', ev.title)
17661 cls: 'ui-resizable-handle ui-resizable-e',
17662 html : '  '
17669 cfg.cls += ' fc-event-start';
17671 if ((i+1) == rows.length) {
17672 cfg.cls += ' fc-event-end';
17675 var ctr = _this.el.select('.fc-event-container',true).first();
17676 var cg = ctr.createChild(cfg);
17678 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17679 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17681 var r = (c.more.length) ? 1 : 0;
17682 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17683 cg.setWidth(ebox.right - sbox.x -2);
17685 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17686 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17687 cg.on('click', _this.onEventClick, _this, ev);
17698 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17699 style : 'position: absolute',
17700 unselectable : "on",
17703 cls: 'fc-event-inner',
17707 cls: 'fc-event-title',
17715 cls: 'ui-resizable-handle ui-resizable-e',
17716 html : '  '
17722 var ctr = _this.el.select('.fc-event-container',true).first();
17723 var cg = ctr.createChild(cfg);
17725 var sbox = c.select('.fc-day-content',true).first().getBox();
17726 var ebox = c.select('.fc-day-content',true).first().getBox();
17728 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17729 cg.setWidth(ebox.right - sbox.x -2);
17731 cg.on('click', _this.onMoreEventClick, _this, c.more);
17741 onEventEnter: function (e, el,event,d) {
17742 this.fireEvent('evententer', this, el, event);
17745 onEventLeave: function (e, el,event,d) {
17746 this.fireEvent('eventleave', this, el, event);
17749 onEventClick: function (e, el,event,d) {
17750 this.fireEvent('eventclick', this, el, event);
17753 onMonthChange: function () {
17757 onMoreEventClick: function(e, el, more)
17761 this.calpopover.placement = 'right';
17762 this.calpopover.setTitle('More');
17764 this.calpopover.setContent('');
17766 var ctr = this.calpopover.el.select('.popover-content', true).first();
17768 Roo.each(more, function(m){
17770 cls : 'fc-event-hori fc-event-draggable',
17773 var cg = ctr.createChild(cfg);
17775 cg.on('click', _this.onEventClick, _this, m);
17778 this.calpopover.show(el);
17783 onLoad: function ()
17785 this.calevents = [];
17788 if(this.store.getCount() > 0){
17789 this.store.data.each(function(d){
17792 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17793 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17794 time : d.data.start_time,
17795 title : d.data.title,
17796 description : d.data.description,
17797 venue : d.data.venue
17802 this.renderEvents();
17804 if(this.calevents.length && this.loadMask){
17805 this.maskEl.hide();
17809 onBeforeLoad: function()
17811 this.clearEvents();
17813 this.maskEl.show();
17827 * @class Roo.bootstrap.Popover
17828 * @extends Roo.bootstrap.Component
17829 * Bootstrap Popover class
17830 * @cfg {String} html contents of the popover (or false to use children..)
17831 * @cfg {String} title of popover (or false to hide)
17832 * @cfg {String} placement how it is placed
17833 * @cfg {String} trigger click || hover (or false to trigger manually)
17834 * @cfg {String} over what (parent or false to trigger manually.)
17835 * @cfg {Number} delay - delay before showing
17838 * Create a new Popover
17839 * @param {Object} config The config object
17842 Roo.bootstrap.Popover = function(config){
17843 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17849 * After the popover show
17851 * @param {Roo.bootstrap.Popover} this
17856 * After the popover hide
17858 * @param {Roo.bootstrap.Popover} this
17864 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17866 title: 'Fill in a title',
17869 placement : 'right',
17870 trigger : 'hover', // hover
17876 can_build_overlaid : false,
17878 getChildContainer : function()
17880 return this.el.select('.popover-content',true).first();
17883 getAutoCreate : function(){
17886 cls : 'popover roo-dynamic',
17887 style: 'display:block',
17893 cls : 'popover-inner',
17897 cls: 'popover-title popover-header',
17901 cls : 'popover-content popover-body',
17912 setTitle: function(str)
17915 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17917 setContent: function(str)
17920 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17922 // as it get's added to the bottom of the page.
17923 onRender : function(ct, position)
17925 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17927 var cfg = Roo.apply({}, this.getAutoCreate());
17931 cfg.cls += ' ' + this.cls;
17934 cfg.style = this.style;
17936 //Roo.log("adding to ");
17937 this.el = Roo.get(document.body).createChild(cfg, position);
17938 // Roo.log(this.el);
17943 initEvents : function()
17945 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17946 this.el.enableDisplayMode('block');
17948 if (this.over === false) {
17951 if (this.triggers === false) {
17954 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17955 var triggers = this.trigger ? this.trigger.split(' ') : [];
17956 Roo.each(triggers, function(trigger) {
17958 if (trigger == 'click') {
17959 on_el.on('click', this.toggle, this);
17960 } else if (trigger != 'manual') {
17961 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17962 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17964 on_el.on(eventIn ,this.enter, this);
17965 on_el.on(eventOut, this.leave, this);
17976 toggle : function () {
17977 this.hoverState == 'in' ? this.leave() : this.enter();
17980 enter : function () {
17982 clearTimeout(this.timeout);
17984 this.hoverState = 'in';
17986 if (!this.delay || !this.delay.show) {
17991 this.timeout = setTimeout(function () {
17992 if (_t.hoverState == 'in') {
17995 }, this.delay.show)
17998 leave : function() {
17999 clearTimeout(this.timeout);
18001 this.hoverState = 'out';
18003 if (!this.delay || !this.delay.hide) {
18008 this.timeout = setTimeout(function () {
18009 if (_t.hoverState == 'out') {
18012 }, this.delay.hide)
18015 show : function (on_el)
18018 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18022 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18023 if (this.html !== false) {
18024 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18026 this.el.removeClass([
18027 'fade','top','bottom', 'left', 'right','in',
18028 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18030 if (!this.title.length) {
18031 this.el.select('.popover-title',true).hide();
18034 var placement = typeof this.placement == 'function' ?
18035 this.placement.call(this, this.el, on_el) :
18038 var autoToken = /\s?auto?\s?/i;
18039 var autoPlace = autoToken.test(placement);
18041 placement = placement.replace(autoToken, '') || 'top';
18045 //this.el.setXY([0,0]);
18047 this.el.dom.style.display='block';
18048 this.el.addClass(placement);
18050 //this.el.appendTo(on_el);
18052 var p = this.getPosition();
18053 var box = this.el.getBox();
18058 var align = Roo.bootstrap.Popover.alignment[placement];
18061 this.el.alignTo(on_el, align[0],align[1]);
18062 //var arrow = this.el.select('.arrow',true).first();
18063 //arrow.set(align[2],
18065 this.el.addClass('in');
18068 if (this.el.hasClass('fade')) {
18072 this.hoverState = 'in';
18074 this.fireEvent('show', this);
18079 this.el.setXY([0,0]);
18080 this.el.removeClass('in');
18082 this.hoverState = null;
18084 this.fireEvent('hide', this);
18089 Roo.bootstrap.Popover.alignment = {
18090 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18091 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18092 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18093 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18104 * @class Roo.bootstrap.Progress
18105 * @extends Roo.bootstrap.Component
18106 * Bootstrap Progress class
18107 * @cfg {Boolean} striped striped of the progress bar
18108 * @cfg {Boolean} active animated of the progress bar
18112 * Create a new Progress
18113 * @param {Object} config The config object
18116 Roo.bootstrap.Progress = function(config){
18117 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18120 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18125 getAutoCreate : function(){
18133 cfg.cls += ' progress-striped';
18137 cfg.cls += ' active';
18156 * @class Roo.bootstrap.ProgressBar
18157 * @extends Roo.bootstrap.Component
18158 * Bootstrap ProgressBar class
18159 * @cfg {Number} aria_valuenow aria-value now
18160 * @cfg {Number} aria_valuemin aria-value min
18161 * @cfg {Number} aria_valuemax aria-value max
18162 * @cfg {String} label label for the progress bar
18163 * @cfg {String} panel (success | info | warning | danger )
18164 * @cfg {String} role role of the progress bar
18165 * @cfg {String} sr_only text
18169 * Create a new ProgressBar
18170 * @param {Object} config The config object
18173 Roo.bootstrap.ProgressBar = function(config){
18174 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18177 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18181 aria_valuemax : 100,
18187 getAutoCreate : function()
18192 cls: 'progress-bar',
18193 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18205 cfg.role = this.role;
18208 if(this.aria_valuenow){
18209 cfg['aria-valuenow'] = this.aria_valuenow;
18212 if(this.aria_valuemin){
18213 cfg['aria-valuemin'] = this.aria_valuemin;
18216 if(this.aria_valuemax){
18217 cfg['aria-valuemax'] = this.aria_valuemax;
18220 if(this.label && !this.sr_only){
18221 cfg.html = this.label;
18225 cfg.cls += ' progress-bar-' + this.panel;
18231 update : function(aria_valuenow)
18233 this.aria_valuenow = aria_valuenow;
18235 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18250 * @class Roo.bootstrap.TabGroup
18251 * @extends Roo.bootstrap.Column
18252 * Bootstrap Column class
18253 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18254 * @cfg {Boolean} carousel true to make the group behave like a carousel
18255 * @cfg {Boolean} bullets show bullets for the panels
18256 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18257 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18258 * @cfg {Boolean} showarrow (true|false) show arrow default true
18261 * Create a new TabGroup
18262 * @param {Object} config The config object
18265 Roo.bootstrap.TabGroup = function(config){
18266 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18268 this.navId = Roo.id();
18271 Roo.bootstrap.TabGroup.register(this);
18275 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18278 transition : false,
18283 slideOnTouch : false,
18286 getAutoCreate : function()
18288 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18290 cfg.cls += ' tab-content';
18292 if (this.carousel) {
18293 cfg.cls += ' carousel slide';
18296 cls : 'carousel-inner',
18300 if(this.bullets && !Roo.isTouch){
18303 cls : 'carousel-bullets',
18307 if(this.bullets_cls){
18308 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18315 cfg.cn[0].cn.push(bullets);
18318 if(this.showarrow){
18319 cfg.cn[0].cn.push({
18321 class : 'carousel-arrow',
18325 class : 'carousel-prev',
18329 class : 'fa fa-chevron-left'
18335 class : 'carousel-next',
18339 class : 'fa fa-chevron-right'
18352 initEvents: function()
18354 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18355 // this.el.on("touchstart", this.onTouchStart, this);
18358 if(this.autoslide){
18361 this.slideFn = window.setInterval(function() {
18362 _this.showPanelNext();
18366 if(this.showarrow){
18367 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18368 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18374 // onTouchStart : function(e, el, o)
18376 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18380 // this.showPanelNext();
18384 getChildContainer : function()
18386 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18390 * register a Navigation item
18391 * @param {Roo.bootstrap.NavItem} the navitem to add
18393 register : function(item)
18395 this.tabs.push( item);
18396 item.navId = this.navId; // not really needed..
18401 getActivePanel : function()
18404 Roo.each(this.tabs, function(t) {
18414 getPanelByName : function(n)
18417 Roo.each(this.tabs, function(t) {
18418 if (t.tabId == n) {
18426 indexOfPanel : function(p)
18429 Roo.each(this.tabs, function(t,i) {
18430 if (t.tabId == p.tabId) {
18439 * show a specific panel
18440 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18441 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18443 showPanel : function (pan)
18445 if(this.transition || typeof(pan) == 'undefined'){
18446 Roo.log("waiting for the transitionend");
18450 if (typeof(pan) == 'number') {
18451 pan = this.tabs[pan];
18454 if (typeof(pan) == 'string') {
18455 pan = this.getPanelByName(pan);
18458 var cur = this.getActivePanel();
18461 Roo.log('pan or acitve pan is undefined');
18465 if (pan.tabId == this.getActivePanel().tabId) {
18469 if (false === cur.fireEvent('beforedeactivate')) {
18473 if(this.bullets > 0 && !Roo.isTouch){
18474 this.setActiveBullet(this.indexOfPanel(pan));
18477 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18479 //class="carousel-item carousel-item-next carousel-item-left"
18481 this.transition = true;
18482 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18483 var lr = dir == 'next' ? 'left' : 'right';
18484 pan.el.addClass(dir); // or prev
18485 pan.el.addClass('carousel-item-' + dir); // or prev
18486 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18487 cur.el.addClass(lr); // or right
18488 pan.el.addClass(lr);
18489 cur.el.addClass('carousel-item-' +lr); // or right
18490 pan.el.addClass('carousel-item-' +lr);
18494 cur.el.on('transitionend', function() {
18495 Roo.log("trans end?");
18497 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18498 pan.setActive(true);
18500 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18501 cur.setActive(false);
18503 _this.transition = false;
18505 }, this, { single: true } );
18510 cur.setActive(false);
18511 pan.setActive(true);
18516 showPanelNext : function()
18518 var i = this.indexOfPanel(this.getActivePanel());
18520 if (i >= this.tabs.length - 1 && !this.autoslide) {
18524 if (i >= this.tabs.length - 1 && this.autoslide) {
18528 this.showPanel(this.tabs[i+1]);
18531 showPanelPrev : function()
18533 var i = this.indexOfPanel(this.getActivePanel());
18535 if (i < 1 && !this.autoslide) {
18539 if (i < 1 && this.autoslide) {
18540 i = this.tabs.length;
18543 this.showPanel(this.tabs[i-1]);
18547 addBullet: function()
18549 if(!this.bullets || Roo.isTouch){
18552 var ctr = this.el.select('.carousel-bullets',true).first();
18553 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18554 var bullet = ctr.createChild({
18555 cls : 'bullet bullet-' + i
18556 },ctr.dom.lastChild);
18561 bullet.on('click', (function(e, el, o, ii, t){
18563 e.preventDefault();
18565 this.showPanel(ii);
18567 if(this.autoslide && this.slideFn){
18568 clearInterval(this.slideFn);
18569 this.slideFn = window.setInterval(function() {
18570 _this.showPanelNext();
18574 }).createDelegate(this, [i, bullet], true));
18579 setActiveBullet : function(i)
18585 Roo.each(this.el.select('.bullet', true).elements, function(el){
18586 el.removeClass('selected');
18589 var bullet = this.el.select('.bullet-' + i, true).first();
18595 bullet.addClass('selected');
18606 Roo.apply(Roo.bootstrap.TabGroup, {
18610 * register a Navigation Group
18611 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18613 register : function(navgrp)
18615 this.groups[navgrp.navId] = navgrp;
18619 * fetch a Navigation Group based on the navigation ID
18620 * if one does not exist , it will get created.
18621 * @param {string} the navgroup to add
18622 * @returns {Roo.bootstrap.NavGroup} the navgroup
18624 get: function(navId) {
18625 if (typeof(this.groups[navId]) == 'undefined') {
18626 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18628 return this.groups[navId] ;
18643 * @class Roo.bootstrap.TabPanel
18644 * @extends Roo.bootstrap.Component
18645 * Bootstrap TabPanel class
18646 * @cfg {Boolean} active panel active
18647 * @cfg {String} html panel content
18648 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18649 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18650 * @cfg {String} href click to link..
18654 * Create a new TabPanel
18655 * @param {Object} config The config object
18658 Roo.bootstrap.TabPanel = function(config){
18659 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18663 * Fires when the active status changes
18664 * @param {Roo.bootstrap.TabPanel} this
18665 * @param {Boolean} state the new state
18670 * @event beforedeactivate
18671 * Fires before a tab is de-activated - can be used to do validation on a form.
18672 * @param {Roo.bootstrap.TabPanel} this
18673 * @return {Boolean} false if there is an error
18676 'beforedeactivate': true
18679 this.tabId = this.tabId || Roo.id();
18683 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18691 getAutoCreate : function(){
18696 // item is needed for carousel - not sure if it has any effect otherwise
18697 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18698 html: this.html || ''
18702 cfg.cls += ' active';
18706 cfg.tabId = this.tabId;
18714 initEvents: function()
18716 var p = this.parent();
18718 this.navId = this.navId || p.navId;
18720 if (typeof(this.navId) != 'undefined') {
18721 // not really needed.. but just in case.. parent should be a NavGroup.
18722 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18726 var i = tg.tabs.length - 1;
18728 if(this.active && tg.bullets > 0 && i < tg.bullets){
18729 tg.setActiveBullet(i);
18733 this.el.on('click', this.onClick, this);
18736 this.el.on("touchstart", this.onTouchStart, this);
18737 this.el.on("touchmove", this.onTouchMove, this);
18738 this.el.on("touchend", this.onTouchEnd, this);
18743 onRender : function(ct, position)
18745 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18748 setActive : function(state)
18750 Roo.log("panel - set active " + this.tabId + "=" + state);
18752 this.active = state;
18754 this.el.removeClass('active');
18756 } else if (!this.el.hasClass('active')) {
18757 this.el.addClass('active');
18760 this.fireEvent('changed', this, state);
18763 onClick : function(e)
18765 e.preventDefault();
18767 if(!this.href.length){
18771 window.location.href = this.href;
18780 onTouchStart : function(e)
18782 this.swiping = false;
18784 this.startX = e.browserEvent.touches[0].clientX;
18785 this.startY = e.browserEvent.touches[0].clientY;
18788 onTouchMove : function(e)
18790 this.swiping = true;
18792 this.endX = e.browserEvent.touches[0].clientX;
18793 this.endY = e.browserEvent.touches[0].clientY;
18796 onTouchEnd : function(e)
18803 var tabGroup = this.parent();
18805 if(this.endX > this.startX){ // swiping right
18806 tabGroup.showPanelPrev();
18810 if(this.startX > this.endX){ // swiping left
18811 tabGroup.showPanelNext();
18830 * @class Roo.bootstrap.DateField
18831 * @extends Roo.bootstrap.Input
18832 * Bootstrap DateField class
18833 * @cfg {Number} weekStart default 0
18834 * @cfg {String} viewMode default empty, (months|years)
18835 * @cfg {String} minViewMode default empty, (months|years)
18836 * @cfg {Number} startDate default -Infinity
18837 * @cfg {Number} endDate default Infinity
18838 * @cfg {Boolean} todayHighlight default false
18839 * @cfg {Boolean} todayBtn default false
18840 * @cfg {Boolean} calendarWeeks default false
18841 * @cfg {Object} daysOfWeekDisabled default empty
18842 * @cfg {Boolean} singleMode default false (true | false)
18844 * @cfg {Boolean} keyboardNavigation default true
18845 * @cfg {String} language default en
18848 * Create a new DateField
18849 * @param {Object} config The config object
18852 Roo.bootstrap.DateField = function(config){
18853 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18857 * Fires when this field show.
18858 * @param {Roo.bootstrap.DateField} this
18859 * @param {Mixed} date The date value
18864 * Fires when this field hide.
18865 * @param {Roo.bootstrap.DateField} this
18866 * @param {Mixed} date The date value
18871 * Fires when select a date.
18872 * @param {Roo.bootstrap.DateField} this
18873 * @param {Mixed} date The date value
18877 * @event beforeselect
18878 * Fires when before select a date.
18879 * @param {Roo.bootstrap.DateField} this
18880 * @param {Mixed} date The date value
18882 beforeselect : true
18886 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18889 * @cfg {String} format
18890 * The default date format string which can be overriden for localization support. The format must be
18891 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18895 * @cfg {String} altFormats
18896 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18897 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18899 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18907 todayHighlight : false,
18913 keyboardNavigation: true,
18915 calendarWeeks: false,
18917 startDate: -Infinity,
18921 daysOfWeekDisabled: [],
18925 singleMode : false,
18927 UTCDate: function()
18929 return new Date(Date.UTC.apply(Date, arguments));
18932 UTCToday: function()
18934 var today = new Date();
18935 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18938 getDate: function() {
18939 var d = this.getUTCDate();
18940 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18943 getUTCDate: function() {
18947 setDate: function(d) {
18948 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18951 setUTCDate: function(d) {
18953 this.setValue(this.formatDate(this.date));
18956 onRender: function(ct, position)
18959 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18961 this.language = this.language || 'en';
18962 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18963 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18965 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18966 this.format = this.format || 'm/d/y';
18967 this.isInline = false;
18968 this.isInput = true;
18969 this.component = this.el.select('.add-on', true).first() || false;
18970 this.component = (this.component && this.component.length === 0) ? false : this.component;
18971 this.hasInput = this.component && this.inputEl().length;
18973 if (typeof(this.minViewMode === 'string')) {
18974 switch (this.minViewMode) {
18976 this.minViewMode = 1;
18979 this.minViewMode = 2;
18982 this.minViewMode = 0;
18987 if (typeof(this.viewMode === 'string')) {
18988 switch (this.viewMode) {
19001 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
19003 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
19005 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19007 this.picker().on('mousedown', this.onMousedown, this);
19008 this.picker().on('click', this.onClick, this);
19010 this.picker().addClass('datepicker-dropdown');
19012 this.startViewMode = this.viewMode;
19014 if(this.singleMode){
19015 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19016 v.setVisibilityMode(Roo.Element.DISPLAY);
19020 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19021 v.setStyle('width', '189px');
19025 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19026 if(!this.calendarWeeks){
19031 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19032 v.attr('colspan', function(i, val){
19033 return parseInt(val) + 1;
19038 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19040 this.setStartDate(this.startDate);
19041 this.setEndDate(this.endDate);
19043 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19050 if(this.isInline) {
19055 picker : function()
19057 return this.pickerEl;
19058 // return this.el.select('.datepicker', true).first();
19061 fillDow: function()
19063 var dowCnt = this.weekStart;
19072 if(this.calendarWeeks){
19080 while (dowCnt < this.weekStart + 7) {
19084 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19088 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19091 fillMonths: function()
19094 var months = this.picker().select('>.datepicker-months td', true).first();
19096 months.dom.innerHTML = '';
19102 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19105 months.createChild(month);
19112 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;
19114 if (this.date < this.startDate) {
19115 this.viewDate = new Date(this.startDate);
19116 } else if (this.date > this.endDate) {
19117 this.viewDate = new Date(this.endDate);
19119 this.viewDate = new Date(this.date);
19127 var d = new Date(this.viewDate),
19128 year = d.getUTCFullYear(),
19129 month = d.getUTCMonth(),
19130 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19131 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19132 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19133 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19134 currentDate = this.date && this.date.valueOf(),
19135 today = this.UTCToday();
19137 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19139 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19141 // this.picker.select('>tfoot th.today').
19142 // .text(dates[this.language].today)
19143 // .toggle(this.todayBtn !== false);
19145 this.updateNavArrows();
19148 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19150 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19152 prevMonth.setUTCDate(day);
19154 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19156 var nextMonth = new Date(prevMonth);
19158 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19160 nextMonth = nextMonth.valueOf();
19162 var fillMonths = false;
19164 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19166 while(prevMonth.valueOf() <= nextMonth) {
19169 if (prevMonth.getUTCDay() === this.weekStart) {
19171 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19179 if(this.calendarWeeks){
19180 // ISO 8601: First week contains first thursday.
19181 // ISO also states week starts on Monday, but we can be more abstract here.
19183 // Start of current week: based on weekstart/current date
19184 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19185 // Thursday of this week
19186 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19187 // First Thursday of year, year from thursday
19188 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19189 // Calendar week: ms between thursdays, div ms per day, div 7 days
19190 calWeek = (th - yth) / 864e5 / 7 + 1;
19192 fillMonths.cn.push({
19200 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19202 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19205 if (this.todayHighlight &&
19206 prevMonth.getUTCFullYear() == today.getFullYear() &&
19207 prevMonth.getUTCMonth() == today.getMonth() &&
19208 prevMonth.getUTCDate() == today.getDate()) {
19209 clsName += ' today';
19212 if (currentDate && prevMonth.valueOf() === currentDate) {
19213 clsName += ' active';
19216 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19217 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19218 clsName += ' disabled';
19221 fillMonths.cn.push({
19223 cls: 'day ' + clsName,
19224 html: prevMonth.getDate()
19227 prevMonth.setDate(prevMonth.getDate()+1);
19230 var currentYear = this.date && this.date.getUTCFullYear();
19231 var currentMonth = this.date && this.date.getUTCMonth();
19233 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19235 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19236 v.removeClass('active');
19238 if(currentYear === year && k === currentMonth){
19239 v.addClass('active');
19242 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19243 v.addClass('disabled');
19249 year = parseInt(year/10, 10) * 10;
19251 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19253 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19256 for (var i = -1; i < 11; i++) {
19257 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19259 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19267 showMode: function(dir)
19270 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19273 Roo.each(this.picker().select('>div',true).elements, function(v){
19274 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19277 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19282 if(this.isInline) {
19286 this.picker().removeClass(['bottom', 'top']);
19288 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19290 * place to the top of element!
19294 this.picker().addClass('top');
19295 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19300 this.picker().addClass('bottom');
19302 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19305 parseDate : function(value)
19307 if(!value || value instanceof Date){
19310 var v = Date.parseDate(value, this.format);
19311 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19312 v = Date.parseDate(value, 'Y-m-d');
19314 if(!v && this.altFormats){
19315 if(!this.altFormatsArray){
19316 this.altFormatsArray = this.altFormats.split("|");
19318 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19319 v = Date.parseDate(value, this.altFormatsArray[i]);
19325 formatDate : function(date, fmt)
19327 return (!date || !(date instanceof Date)) ?
19328 date : date.dateFormat(fmt || this.format);
19331 onFocus : function()
19333 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19337 onBlur : function()
19339 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19341 var d = this.inputEl().getValue();
19348 showPopup : function()
19350 this.picker().show();
19354 this.fireEvent('showpopup', this, this.date);
19357 hidePopup : function()
19359 if(this.isInline) {
19362 this.picker().hide();
19363 this.viewMode = this.startViewMode;
19366 this.fireEvent('hidepopup', this, this.date);
19370 onMousedown: function(e)
19372 e.stopPropagation();
19373 e.preventDefault();
19378 Roo.bootstrap.DateField.superclass.keyup.call(this);
19382 setValue: function(v)
19384 if(this.fireEvent('beforeselect', this, v) !== false){
19385 var d = new Date(this.parseDate(v) ).clearTime();
19387 if(isNaN(d.getTime())){
19388 this.date = this.viewDate = '';
19389 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19393 v = this.formatDate(d);
19395 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19397 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19401 this.fireEvent('select', this, this.date);
19405 getValue: function()
19407 return this.formatDate(this.date);
19410 fireKey: function(e)
19412 if (!this.picker().isVisible()){
19413 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19419 var dateChanged = false,
19421 newDate, newViewDate;
19426 e.preventDefault();
19430 if (!this.keyboardNavigation) {
19433 dir = e.keyCode == 37 ? -1 : 1;
19436 newDate = this.moveYear(this.date, dir);
19437 newViewDate = this.moveYear(this.viewDate, dir);
19438 } else if (e.shiftKey){
19439 newDate = this.moveMonth(this.date, dir);
19440 newViewDate = this.moveMonth(this.viewDate, dir);
19442 newDate = new Date(this.date);
19443 newDate.setUTCDate(this.date.getUTCDate() + dir);
19444 newViewDate = new Date(this.viewDate);
19445 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19447 if (this.dateWithinRange(newDate)){
19448 this.date = newDate;
19449 this.viewDate = newViewDate;
19450 this.setValue(this.formatDate(this.date));
19452 e.preventDefault();
19453 dateChanged = true;
19458 if (!this.keyboardNavigation) {
19461 dir = e.keyCode == 38 ? -1 : 1;
19463 newDate = this.moveYear(this.date, dir);
19464 newViewDate = this.moveYear(this.viewDate, dir);
19465 } else if (e.shiftKey){
19466 newDate = this.moveMonth(this.date, dir);
19467 newViewDate = this.moveMonth(this.viewDate, dir);
19469 newDate = new Date(this.date);
19470 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19471 newViewDate = new Date(this.viewDate);
19472 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19474 if (this.dateWithinRange(newDate)){
19475 this.date = newDate;
19476 this.viewDate = newViewDate;
19477 this.setValue(this.formatDate(this.date));
19479 e.preventDefault();
19480 dateChanged = true;
19484 this.setValue(this.formatDate(this.date));
19486 e.preventDefault();
19489 this.setValue(this.formatDate(this.date));
19503 onClick: function(e)
19505 e.stopPropagation();
19506 e.preventDefault();
19508 var target = e.getTarget();
19510 if(target.nodeName.toLowerCase() === 'i'){
19511 target = Roo.get(target).dom.parentNode;
19514 var nodeName = target.nodeName;
19515 var className = target.className;
19516 var html = target.innerHTML;
19517 //Roo.log(nodeName);
19519 switch(nodeName.toLowerCase()) {
19521 switch(className) {
19527 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19528 switch(this.viewMode){
19530 this.viewDate = this.moveMonth(this.viewDate, dir);
19534 this.viewDate = this.moveYear(this.viewDate, dir);
19540 var date = new Date();
19541 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19543 this.setValue(this.formatDate(this.date));
19550 if (className.indexOf('disabled') < 0) {
19551 this.viewDate.setUTCDate(1);
19552 if (className.indexOf('month') > -1) {
19553 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19555 var year = parseInt(html, 10) || 0;
19556 this.viewDate.setUTCFullYear(year);
19560 if(this.singleMode){
19561 this.setValue(this.formatDate(this.viewDate));
19572 //Roo.log(className);
19573 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19574 var day = parseInt(html, 10) || 1;
19575 var year = this.viewDate.getUTCFullYear(),
19576 month = this.viewDate.getUTCMonth();
19578 if (className.indexOf('old') > -1) {
19585 } else if (className.indexOf('new') > -1) {
19593 //Roo.log([year,month,day]);
19594 this.date = this.UTCDate(year, month, day,0,0,0,0);
19595 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19597 //Roo.log(this.formatDate(this.date));
19598 this.setValue(this.formatDate(this.date));
19605 setStartDate: function(startDate)
19607 this.startDate = startDate || -Infinity;
19608 if (this.startDate !== -Infinity) {
19609 this.startDate = this.parseDate(this.startDate);
19612 this.updateNavArrows();
19615 setEndDate: function(endDate)
19617 this.endDate = endDate || Infinity;
19618 if (this.endDate !== Infinity) {
19619 this.endDate = this.parseDate(this.endDate);
19622 this.updateNavArrows();
19625 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19627 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19628 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19629 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19631 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19632 return parseInt(d, 10);
19635 this.updateNavArrows();
19638 updateNavArrows: function()
19640 if(this.singleMode){
19644 var d = new Date(this.viewDate),
19645 year = d.getUTCFullYear(),
19646 month = d.getUTCMonth();
19648 Roo.each(this.picker().select('.prev', true).elements, function(v){
19650 switch (this.viewMode) {
19653 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19659 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19666 Roo.each(this.picker().select('.next', true).elements, function(v){
19668 switch (this.viewMode) {
19671 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19677 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19685 moveMonth: function(date, dir)
19690 var new_date = new Date(date.valueOf()),
19691 day = new_date.getUTCDate(),
19692 month = new_date.getUTCMonth(),
19693 mag = Math.abs(dir),
19695 dir = dir > 0 ? 1 : -1;
19698 // If going back one month, make sure month is not current month
19699 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19701 return new_date.getUTCMonth() == month;
19703 // If going forward one month, make sure month is as expected
19704 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19706 return new_date.getUTCMonth() != new_month;
19708 new_month = month + dir;
19709 new_date.setUTCMonth(new_month);
19710 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19711 if (new_month < 0 || new_month > 11) {
19712 new_month = (new_month + 12) % 12;
19715 // For magnitudes >1, move one month at a time...
19716 for (var i=0; i<mag; i++) {
19717 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19718 new_date = this.moveMonth(new_date, dir);
19720 // ...then reset the day, keeping it in the new month
19721 new_month = new_date.getUTCMonth();
19722 new_date.setUTCDate(day);
19724 return new_month != new_date.getUTCMonth();
19727 // Common date-resetting loop -- if date is beyond end of month, make it
19730 new_date.setUTCDate(--day);
19731 new_date.setUTCMonth(new_month);
19736 moveYear: function(date, dir)
19738 return this.moveMonth(date, dir*12);
19741 dateWithinRange: function(date)
19743 return date >= this.startDate && date <= this.endDate;
19749 this.picker().remove();
19752 validateValue : function(value)
19754 if(this.getVisibilityEl().hasClass('hidden')){
19758 if(value.length < 1) {
19759 if(this.allowBlank){
19765 if(value.length < this.minLength){
19768 if(value.length > this.maxLength){
19772 var vt = Roo.form.VTypes;
19773 if(!vt[this.vtype](value, this)){
19777 if(typeof this.validator == "function"){
19778 var msg = this.validator(value);
19784 if(this.regex && !this.regex.test(value)){
19788 if(typeof(this.parseDate(value)) == 'undefined'){
19792 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19796 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19806 this.date = this.viewDate = '';
19808 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19813 Roo.apply(Roo.bootstrap.DateField, {
19824 html: '<i class="fa fa-arrow-left"/>'
19834 html: '<i class="fa fa-arrow-right"/>'
19876 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19877 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19878 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19879 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19880 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19893 navFnc: 'FullYear',
19898 navFnc: 'FullYear',
19903 Roo.apply(Roo.bootstrap.DateField, {
19907 cls: 'datepicker dropdown-menu roo-dynamic',
19911 cls: 'datepicker-days',
19915 cls: 'table-condensed',
19917 Roo.bootstrap.DateField.head,
19921 Roo.bootstrap.DateField.footer
19928 cls: 'datepicker-months',
19932 cls: 'table-condensed',
19934 Roo.bootstrap.DateField.head,
19935 Roo.bootstrap.DateField.content,
19936 Roo.bootstrap.DateField.footer
19943 cls: 'datepicker-years',
19947 cls: 'table-condensed',
19949 Roo.bootstrap.DateField.head,
19950 Roo.bootstrap.DateField.content,
19951 Roo.bootstrap.DateField.footer
19970 * @class Roo.bootstrap.TimeField
19971 * @extends Roo.bootstrap.Input
19972 * Bootstrap DateField class
19976 * Create a new TimeField
19977 * @param {Object} config The config object
19980 Roo.bootstrap.TimeField = function(config){
19981 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19985 * Fires when this field show.
19986 * @param {Roo.bootstrap.DateField} thisthis
19987 * @param {Mixed} date The date value
19992 * Fires when this field hide.
19993 * @param {Roo.bootstrap.DateField} this
19994 * @param {Mixed} date The date value
19999 * Fires when select a date.
20000 * @param {Roo.bootstrap.DateField} this
20001 * @param {Mixed} date The date value
20007 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20010 * @cfg {String} format
20011 * The default time format string which can be overriden for localization support. The format must be
20012 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20016 onRender: function(ct, position)
20019 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20021 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20023 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20025 this.pop = this.picker().select('>.datepicker-time',true).first();
20026 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20028 this.picker().on('mousedown', this.onMousedown, this);
20029 this.picker().on('click', this.onClick, this);
20031 this.picker().addClass('datepicker-dropdown');
20036 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20037 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20038 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20039 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20040 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20041 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20045 fireKey: function(e){
20046 if (!this.picker().isVisible()){
20047 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20053 e.preventDefault();
20061 this.onTogglePeriod();
20064 this.onIncrementMinutes();
20067 this.onDecrementMinutes();
20076 onClick: function(e) {
20077 e.stopPropagation();
20078 e.preventDefault();
20081 picker : function()
20083 return this.el.select('.datepicker', true).first();
20086 fillTime: function()
20088 var time = this.pop.select('tbody', true).first();
20090 time.dom.innerHTML = '';
20105 cls: 'hours-up glyphicon glyphicon-chevron-up'
20125 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20146 cls: 'timepicker-hour',
20161 cls: 'timepicker-minute',
20176 cls: 'btn btn-primary period',
20198 cls: 'hours-down glyphicon glyphicon-chevron-down'
20218 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20236 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20243 var hours = this.time.getHours();
20244 var minutes = this.time.getMinutes();
20257 hours = hours - 12;
20261 hours = '0' + hours;
20265 minutes = '0' + minutes;
20268 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20269 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20270 this.pop.select('button', true).first().dom.innerHTML = period;
20276 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20278 var cls = ['bottom'];
20280 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20287 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20292 this.picker().addClass(cls.join('-'));
20296 Roo.each(cls, function(c){
20298 _this.picker().setTop(_this.inputEl().getHeight());
20302 _this.picker().setTop(0 - _this.picker().getHeight());
20307 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20311 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20318 onFocus : function()
20320 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20324 onBlur : function()
20326 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20332 this.picker().show();
20337 this.fireEvent('show', this, this.date);
20342 this.picker().hide();
20345 this.fireEvent('hide', this, this.date);
20348 setTime : function()
20351 this.setValue(this.time.format(this.format));
20353 this.fireEvent('select', this, this.date);
20358 onMousedown: function(e){
20359 e.stopPropagation();
20360 e.preventDefault();
20363 onIncrementHours: function()
20365 Roo.log('onIncrementHours');
20366 this.time = this.time.add(Date.HOUR, 1);
20371 onDecrementHours: function()
20373 Roo.log('onDecrementHours');
20374 this.time = this.time.add(Date.HOUR, -1);
20378 onIncrementMinutes: function()
20380 Roo.log('onIncrementMinutes');
20381 this.time = this.time.add(Date.MINUTE, 1);
20385 onDecrementMinutes: function()
20387 Roo.log('onDecrementMinutes');
20388 this.time = this.time.add(Date.MINUTE, -1);
20392 onTogglePeriod: function()
20394 Roo.log('onTogglePeriod');
20395 this.time = this.time.add(Date.HOUR, 12);
20402 Roo.apply(Roo.bootstrap.TimeField, {
20432 cls: 'btn btn-info ok',
20444 Roo.apply(Roo.bootstrap.TimeField, {
20448 cls: 'datepicker dropdown-menu',
20452 cls: 'datepicker-time',
20456 cls: 'table-condensed',
20458 Roo.bootstrap.TimeField.content,
20459 Roo.bootstrap.TimeField.footer
20478 * @class Roo.bootstrap.MonthField
20479 * @extends Roo.bootstrap.Input
20480 * Bootstrap MonthField class
20482 * @cfg {String} language default en
20485 * Create a new MonthField
20486 * @param {Object} config The config object
20489 Roo.bootstrap.MonthField = function(config){
20490 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20495 * Fires when this field show.
20496 * @param {Roo.bootstrap.MonthField} this
20497 * @param {Mixed} date The date value
20502 * Fires when this field hide.
20503 * @param {Roo.bootstrap.MonthField} this
20504 * @param {Mixed} date The date value
20509 * Fires when select a date.
20510 * @param {Roo.bootstrap.MonthField} this
20511 * @param {String} oldvalue The old value
20512 * @param {String} newvalue The new value
20518 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20520 onRender: function(ct, position)
20523 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20525 this.language = this.language || 'en';
20526 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20527 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20529 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20530 this.isInline = false;
20531 this.isInput = true;
20532 this.component = this.el.select('.add-on', true).first() || false;
20533 this.component = (this.component && this.component.length === 0) ? false : this.component;
20534 this.hasInput = this.component && this.inputEL().length;
20536 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20538 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20540 this.picker().on('mousedown', this.onMousedown, this);
20541 this.picker().on('click', this.onClick, this);
20543 this.picker().addClass('datepicker-dropdown');
20545 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20546 v.setStyle('width', '189px');
20553 if(this.isInline) {
20559 setValue: function(v, suppressEvent)
20561 var o = this.getValue();
20563 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20567 if(suppressEvent !== true){
20568 this.fireEvent('select', this, o, v);
20573 getValue: function()
20578 onClick: function(e)
20580 e.stopPropagation();
20581 e.preventDefault();
20583 var target = e.getTarget();
20585 if(target.nodeName.toLowerCase() === 'i'){
20586 target = Roo.get(target).dom.parentNode;
20589 var nodeName = target.nodeName;
20590 var className = target.className;
20591 var html = target.innerHTML;
20593 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20597 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20599 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20605 picker : function()
20607 return this.pickerEl;
20610 fillMonths: function()
20613 var months = this.picker().select('>.datepicker-months td', true).first();
20615 months.dom.innerHTML = '';
20621 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20624 months.createChild(month);
20633 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20634 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20637 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20638 e.removeClass('active');
20640 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20641 e.addClass('active');
20648 if(this.isInline) {
20652 this.picker().removeClass(['bottom', 'top']);
20654 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20656 * place to the top of element!
20660 this.picker().addClass('top');
20661 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20666 this.picker().addClass('bottom');
20668 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20671 onFocus : function()
20673 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20677 onBlur : function()
20679 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20681 var d = this.inputEl().getValue();
20690 this.picker().show();
20691 this.picker().select('>.datepicker-months', true).first().show();
20695 this.fireEvent('show', this, this.date);
20700 if(this.isInline) {
20703 this.picker().hide();
20704 this.fireEvent('hide', this, this.date);
20708 onMousedown: function(e)
20710 e.stopPropagation();
20711 e.preventDefault();
20716 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20720 fireKey: function(e)
20722 if (!this.picker().isVisible()){
20723 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20734 e.preventDefault();
20738 dir = e.keyCode == 37 ? -1 : 1;
20740 this.vIndex = this.vIndex + dir;
20742 if(this.vIndex < 0){
20746 if(this.vIndex > 11){
20750 if(isNaN(this.vIndex)){
20754 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20760 dir = e.keyCode == 38 ? -1 : 1;
20762 this.vIndex = this.vIndex + dir * 4;
20764 if(this.vIndex < 0){
20768 if(this.vIndex > 11){
20772 if(isNaN(this.vIndex)){
20776 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20781 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20782 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20786 e.preventDefault();
20789 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20790 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20806 this.picker().remove();
20811 Roo.apply(Roo.bootstrap.MonthField, {
20830 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20831 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20836 Roo.apply(Roo.bootstrap.MonthField, {
20840 cls: 'datepicker dropdown-menu roo-dynamic',
20844 cls: 'datepicker-months',
20848 cls: 'table-condensed',
20850 Roo.bootstrap.DateField.content
20870 * @class Roo.bootstrap.CheckBox
20871 * @extends Roo.bootstrap.Input
20872 * Bootstrap CheckBox class
20874 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20875 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20876 * @cfg {String} boxLabel The text that appears beside the checkbox
20877 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20878 * @cfg {Boolean} checked initnal the element
20879 * @cfg {Boolean} inline inline the element (default false)
20880 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20881 * @cfg {String} tooltip label tooltip
20884 * Create a new CheckBox
20885 * @param {Object} config The config object
20888 Roo.bootstrap.CheckBox = function(config){
20889 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20894 * Fires when the element is checked or unchecked.
20895 * @param {Roo.bootstrap.CheckBox} this This input
20896 * @param {Boolean} checked The new checked value
20901 * Fires when the element is click.
20902 * @param {Roo.bootstrap.CheckBox} this This input
20909 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20911 inputType: 'checkbox',
20920 getAutoCreate : function()
20922 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20928 cfg.cls = 'form-group ' + this.inputType; //input-group
20931 cfg.cls += ' ' + this.inputType + '-inline';
20937 type : this.inputType,
20938 value : this.inputValue,
20939 cls : 'roo-' + this.inputType, //'form-box',
20940 placeholder : this.placeholder || ''
20944 if(this.inputType != 'radio'){
20948 cls : 'roo-hidden-value',
20949 value : this.checked ? this.inputValue : this.valueOff
20954 if (this.weight) { // Validity check?
20955 cfg.cls += " " + this.inputType + "-" + this.weight;
20958 if (this.disabled) {
20959 input.disabled=true;
20963 input.checked = this.checked;
20968 input.name = this.name;
20970 if(this.inputType != 'radio'){
20971 hidden.name = this.name;
20972 input.name = '_hidden_' + this.name;
20977 input.cls += ' input-' + this.size;
20982 ['xs','sm','md','lg'].map(function(size){
20983 if (settings[size]) {
20984 cfg.cls += ' col-' + size + '-' + settings[size];
20988 var inputblock = input;
20990 if (this.before || this.after) {
20993 cls : 'input-group',
20998 inputblock.cn.push({
21000 cls : 'input-group-addon',
21005 inputblock.cn.push(input);
21007 if(this.inputType != 'radio'){
21008 inputblock.cn.push(hidden);
21012 inputblock.cn.push({
21014 cls : 'input-group-addon',
21021 if (align ==='left' && this.fieldLabel.length) {
21022 // Roo.log("left and has label");
21027 cls : 'control-label',
21028 html : this.fieldLabel
21038 if(this.labelWidth > 12){
21039 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21042 if(this.labelWidth < 13 && this.labelmd == 0){
21043 this.labelmd = this.labelWidth;
21046 if(this.labellg > 0){
21047 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21048 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21051 if(this.labelmd > 0){
21052 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21053 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21056 if(this.labelsm > 0){
21057 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21058 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21061 if(this.labelxs > 0){
21062 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21063 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21066 } else if ( this.fieldLabel.length) {
21067 // Roo.log(" label");
21071 tag: this.boxLabel ? 'span' : 'label',
21073 cls: 'control-label box-input-label',
21074 //cls : 'input-group-addon',
21075 html : this.fieldLabel
21084 // Roo.log(" no label && no align");
21085 cfg.cn = [ inputblock ] ;
21091 var boxLabelCfg = {
21093 //'for': id, // box label is handled by onclick - so no for...
21095 html: this.boxLabel
21099 boxLabelCfg.tooltip = this.tooltip;
21102 cfg.cn.push(boxLabelCfg);
21105 if(this.inputType != 'radio'){
21106 cfg.cn.push(hidden);
21114 * return the real input element.
21116 inputEl: function ()
21118 return this.el.select('input.roo-' + this.inputType,true).first();
21120 hiddenEl: function ()
21122 return this.el.select('input.roo-hidden-value',true).first();
21125 labelEl: function()
21127 return this.el.select('label.control-label',true).first();
21129 /* depricated... */
21133 return this.labelEl();
21136 boxLabelEl: function()
21138 return this.el.select('label.box-label',true).first();
21141 initEvents : function()
21143 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21145 this.inputEl().on('click', this.onClick, this);
21147 if (this.boxLabel) {
21148 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21151 this.startValue = this.getValue();
21154 Roo.bootstrap.CheckBox.register(this);
21158 onClick : function(e)
21160 if(this.fireEvent('click', this, e) !== false){
21161 this.setChecked(!this.checked);
21166 setChecked : function(state,suppressEvent)
21168 this.startValue = this.getValue();
21170 if(this.inputType == 'radio'){
21172 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21173 e.dom.checked = false;
21176 this.inputEl().dom.checked = true;
21178 this.inputEl().dom.value = this.inputValue;
21180 if(suppressEvent !== true){
21181 this.fireEvent('check', this, true);
21189 this.checked = state;
21191 this.inputEl().dom.checked = state;
21194 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21196 if(suppressEvent !== true){
21197 this.fireEvent('check', this, state);
21203 getValue : function()
21205 if(this.inputType == 'radio'){
21206 return this.getGroupValue();
21209 return this.hiddenEl().dom.value;
21213 getGroupValue : function()
21215 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21219 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21222 setValue : function(v,suppressEvent)
21224 if(this.inputType == 'radio'){
21225 this.setGroupValue(v, suppressEvent);
21229 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21234 setGroupValue : function(v, suppressEvent)
21236 this.startValue = this.getValue();
21238 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21239 e.dom.checked = false;
21241 if(e.dom.value == v){
21242 e.dom.checked = true;
21246 if(suppressEvent !== true){
21247 this.fireEvent('check', this, true);
21255 validate : function()
21257 if(this.getVisibilityEl().hasClass('hidden')){
21263 (this.inputType == 'radio' && this.validateRadio()) ||
21264 (this.inputType == 'checkbox' && this.validateCheckbox())
21270 this.markInvalid();
21274 validateRadio : function()
21276 if(this.getVisibilityEl().hasClass('hidden')){
21280 if(this.allowBlank){
21286 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21287 if(!e.dom.checked){
21299 validateCheckbox : function()
21302 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21303 //return (this.getValue() == this.inputValue) ? true : false;
21306 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21314 for(var i in group){
21315 if(group[i].el.isVisible(true)){
21323 for(var i in group){
21328 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21335 * Mark this field as valid
21337 markValid : function()
21341 this.fireEvent('valid', this);
21343 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21346 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21353 if(this.inputType == 'radio'){
21354 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21355 var fg = e.findParent('.form-group', false, true);
21356 if (Roo.bootstrap.version == 3) {
21357 fg.removeClass([_this.invalidClass, _this.validClass]);
21358 fg.addClass(_this.validClass);
21360 fg.removeClass(['is-valid', 'is-invalid']);
21361 fg.addClass('is-valid');
21369 var fg = this.el.findParent('.form-group', false, true);
21370 if (Roo.bootstrap.version == 3) {
21371 fg.removeClass([this.invalidClass, this.validClass]);
21372 fg.addClass(this.validClass);
21374 fg.removeClass(['is-valid', 'is-invalid']);
21375 fg.addClass('is-valid');
21380 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21386 for(var i in group){
21387 var fg = group[i].el.findParent('.form-group', false, true);
21388 if (Roo.bootstrap.version == 3) {
21389 fg.removeClass([this.invalidClass, this.validClass]);
21390 fg.addClass(this.validClass);
21392 fg.removeClass(['is-valid', 'is-invalid']);
21393 fg.addClass('is-valid');
21399 * Mark this field as invalid
21400 * @param {String} msg The validation message
21402 markInvalid : function(msg)
21404 if(this.allowBlank){
21410 this.fireEvent('invalid', this, msg);
21412 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21415 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21419 label.markInvalid();
21422 if(this.inputType == 'radio'){
21424 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21425 var fg = e.findParent('.form-group', false, true);
21426 if (Roo.bootstrap.version == 3) {
21427 fg.removeClass([_this.invalidClass, _this.validClass]);
21428 fg.addClass(_this.invalidClass);
21430 fg.removeClass(['is-invalid', 'is-valid']);
21431 fg.addClass('is-invalid');
21439 var fg = this.el.findParent('.form-group', false, true);
21440 if (Roo.bootstrap.version == 3) {
21441 fg.removeClass([_this.invalidClass, _this.validClass]);
21442 fg.addClass(_this.invalidClass);
21444 fg.removeClass(['is-invalid', 'is-valid']);
21445 fg.addClass('is-invalid');
21450 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21456 for(var i in group){
21457 var fg = group[i].el.findParent('.form-group', false, true);
21458 if (Roo.bootstrap.version == 3) {
21459 fg.removeClass([_this.invalidClass, _this.validClass]);
21460 fg.addClass(_this.invalidClass);
21462 fg.removeClass(['is-invalid', 'is-valid']);
21463 fg.addClass('is-invalid');
21469 clearInvalid : function()
21471 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21473 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21475 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21477 if (label && label.iconEl) {
21478 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21479 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21483 disable : function()
21485 if(this.inputType != 'radio'){
21486 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21493 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21494 _this.getActionEl().addClass(this.disabledClass);
21495 e.dom.disabled = true;
21499 this.disabled = true;
21500 this.fireEvent("disable", this);
21504 enable : function()
21506 if(this.inputType != 'radio'){
21507 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21514 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21515 _this.getActionEl().removeClass(this.disabledClass);
21516 e.dom.disabled = false;
21520 this.disabled = false;
21521 this.fireEvent("enable", this);
21525 setBoxLabel : function(v)
21530 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21536 Roo.apply(Roo.bootstrap.CheckBox, {
21541 * register a CheckBox Group
21542 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21544 register : function(checkbox)
21546 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21547 this.groups[checkbox.groupId] = {};
21550 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21554 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21558 * fetch a CheckBox Group based on the group ID
21559 * @param {string} the group ID
21560 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21562 get: function(groupId) {
21563 if (typeof(this.groups[groupId]) == 'undefined') {
21567 return this.groups[groupId] ;
21580 * @class Roo.bootstrap.Radio
21581 * @extends Roo.bootstrap.Component
21582 * Bootstrap Radio class
21583 * @cfg {String} boxLabel - the label associated
21584 * @cfg {String} value - the value of radio
21587 * Create a new Radio
21588 * @param {Object} config The config object
21590 Roo.bootstrap.Radio = function(config){
21591 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21595 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21601 getAutoCreate : function()
21605 cls : 'form-group radio',
21610 html : this.boxLabel
21618 initEvents : function()
21620 this.parent().register(this);
21622 this.el.on('click', this.onClick, this);
21626 onClick : function(e)
21628 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21629 this.setChecked(true);
21633 setChecked : function(state, suppressEvent)
21635 this.parent().setValue(this.value, suppressEvent);
21639 setBoxLabel : function(v)
21644 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21659 * @class Roo.bootstrap.SecurePass
21660 * @extends Roo.bootstrap.Input
21661 * Bootstrap SecurePass class
21665 * Create a new SecurePass
21666 * @param {Object} config The config object
21669 Roo.bootstrap.SecurePass = function (config) {
21670 // these go here, so the translation tool can replace them..
21672 PwdEmpty: "Please type a password, and then retype it to confirm.",
21673 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21674 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21675 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21676 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21677 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21678 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21679 TooWeak: "Your password is Too Weak."
21681 this.meterLabel = "Password strength:";
21682 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21683 this.meterClass = [
21684 "roo-password-meter-tooweak",
21685 "roo-password-meter-weak",
21686 "roo-password-meter-medium",
21687 "roo-password-meter-strong",
21688 "roo-password-meter-grey"
21693 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21696 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21698 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21700 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21701 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21702 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21703 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21704 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21705 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21706 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21716 * @cfg {String/Object} Label for the strength meter (defaults to
21717 * 'Password strength:')
21722 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21723 * ['Weak', 'Medium', 'Strong'])
21726 pwdStrengths: false,
21739 initEvents: function ()
21741 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21743 if (this.el.is('input[type=password]') && Roo.isSafari) {
21744 this.el.on('keydown', this.SafariOnKeyDown, this);
21747 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21750 onRender: function (ct, position)
21752 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21753 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21754 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21756 this.trigger.createChild({
21761 cls: 'roo-password-meter-grey col-xs-12',
21764 //width: this.meterWidth + 'px'
21768 cls: 'roo-password-meter-text'
21774 if (this.hideTrigger) {
21775 this.trigger.setDisplayed(false);
21777 this.setSize(this.width || '', this.height || '');
21780 onDestroy: function ()
21782 if (this.trigger) {
21783 this.trigger.removeAllListeners();
21784 this.trigger.remove();
21787 this.wrap.remove();
21789 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21792 checkStrength: function ()
21794 var pwd = this.inputEl().getValue();
21795 if (pwd == this._lastPwd) {
21800 if (this.ClientSideStrongPassword(pwd)) {
21802 } else if (this.ClientSideMediumPassword(pwd)) {
21804 } else if (this.ClientSideWeakPassword(pwd)) {
21810 Roo.log('strength1: ' + strength);
21812 //var pm = this.trigger.child('div/div/div').dom;
21813 var pm = this.trigger.child('div/div');
21814 pm.removeClass(this.meterClass);
21815 pm.addClass(this.meterClass[strength]);
21818 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21820 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21822 this._lastPwd = pwd;
21826 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21828 this._lastPwd = '';
21830 var pm = this.trigger.child('div/div');
21831 pm.removeClass(this.meterClass);
21832 pm.addClass('roo-password-meter-grey');
21835 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21838 this.inputEl().dom.type='password';
21841 validateValue: function (value)
21844 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21847 if (value.length == 0) {
21848 if (this.allowBlank) {
21849 this.clearInvalid();
21853 this.markInvalid(this.errors.PwdEmpty);
21854 this.errorMsg = this.errors.PwdEmpty;
21862 if ('[\x21-\x7e]*'.match(value)) {
21863 this.markInvalid(this.errors.PwdBadChar);
21864 this.errorMsg = this.errors.PwdBadChar;
21867 if (value.length < 6) {
21868 this.markInvalid(this.errors.PwdShort);
21869 this.errorMsg = this.errors.PwdShort;
21872 if (value.length > 16) {
21873 this.markInvalid(this.errors.PwdLong);
21874 this.errorMsg = this.errors.PwdLong;
21878 if (this.ClientSideStrongPassword(value)) {
21880 } else if (this.ClientSideMediumPassword(value)) {
21882 } else if (this.ClientSideWeakPassword(value)) {
21889 if (strength < 2) {
21890 //this.markInvalid(this.errors.TooWeak);
21891 this.errorMsg = this.errors.TooWeak;
21896 console.log('strength2: ' + strength);
21898 //var pm = this.trigger.child('div/div/div').dom;
21900 var pm = this.trigger.child('div/div');
21901 pm.removeClass(this.meterClass);
21902 pm.addClass(this.meterClass[strength]);
21904 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21906 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21908 this.errorMsg = '';
21912 CharacterSetChecks: function (type)
21915 this.fResult = false;
21918 isctype: function (character, type)
21921 case this.kCapitalLetter:
21922 if (character >= 'A' && character <= 'Z') {
21927 case this.kSmallLetter:
21928 if (character >= 'a' && character <= 'z') {
21934 if (character >= '0' && character <= '9') {
21939 case this.kPunctuation:
21940 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21951 IsLongEnough: function (pwd, size)
21953 return !(pwd == null || isNaN(size) || pwd.length < size);
21956 SpansEnoughCharacterSets: function (word, nb)
21958 if (!this.IsLongEnough(word, nb))
21963 var characterSetChecks = new Array(
21964 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21965 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21968 for (var index = 0; index < word.length; ++index) {
21969 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21970 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21971 characterSetChecks[nCharSet].fResult = true;
21978 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21979 if (characterSetChecks[nCharSet].fResult) {
21984 if (nCharSets < nb) {
21990 ClientSideStrongPassword: function (pwd)
21992 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21995 ClientSideMediumPassword: function (pwd)
21997 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22000 ClientSideWeakPassword: function (pwd)
22002 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22005 })//<script type="text/javascript">
22008 * Based Ext JS Library 1.1.1
22009 * Copyright(c) 2006-2007, Ext JS, LLC.
22015 * @class Roo.HtmlEditorCore
22016 * @extends Roo.Component
22017 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22019 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22022 Roo.HtmlEditorCore = function(config){
22025 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22030 * @event initialize
22031 * Fires when the editor is fully initialized (including the iframe)
22032 * @param {Roo.HtmlEditorCore} this
22037 * Fires when the editor is first receives the focus. Any insertion must wait
22038 * until after this event.
22039 * @param {Roo.HtmlEditorCore} this
22043 * @event beforesync
22044 * Fires before the textarea is updated with content from the editor iframe. Return false
22045 * to cancel the sync.
22046 * @param {Roo.HtmlEditorCore} this
22047 * @param {String} html
22051 * @event beforepush
22052 * Fires before the iframe editor is updated with content from the textarea. Return false
22053 * to cancel the push.
22054 * @param {Roo.HtmlEditorCore} this
22055 * @param {String} html
22060 * Fires when the textarea is updated with content from the editor iframe.
22061 * @param {Roo.HtmlEditorCore} this
22062 * @param {String} html
22067 * Fires when the iframe editor is updated with content from the textarea.
22068 * @param {Roo.HtmlEditorCore} this
22069 * @param {String} html
22074 * @event editorevent
22075 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22076 * @param {Roo.HtmlEditorCore} this
22082 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22084 // defaults : white / black...
22085 this.applyBlacklists();
22092 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22096 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22102 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22107 * @cfg {Number} height (in pixels)
22111 * @cfg {Number} width (in pixels)
22116 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22119 stylesheets: false,
22124 // private properties
22125 validationEvent : false,
22127 initialized : false,
22129 sourceEditMode : false,
22130 onFocus : Roo.emptyFn,
22132 hideMode:'offsets',
22136 // blacklist + whitelisted elements..
22143 * Protected method that will not generally be called directly. It
22144 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22145 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22147 getDocMarkup : function(){
22151 // inherit styels from page...??
22152 if (this.stylesheets === false) {
22154 Roo.get(document.head).select('style').each(function(node) {
22155 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22158 Roo.get(document.head).select('link').each(function(node) {
22159 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22162 } else if (!this.stylesheets.length) {
22164 st = '<style type="text/css">' +
22165 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22168 st = '<style type="text/css">' +
22173 st += '<style type="text/css">' +
22174 'IMG { cursor: pointer } ' +
22177 var cls = 'roo-htmleditor-body';
22179 if(this.bodyCls.length){
22180 cls += ' ' + this.bodyCls;
22183 return '<html><head>' + st +
22184 //<style type="text/css">' +
22185 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22187 ' </head><body class="' + cls + '"></body></html>';
22191 onRender : function(ct, position)
22194 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22195 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22198 this.el.dom.style.border = '0 none';
22199 this.el.dom.setAttribute('tabIndex', -1);
22200 this.el.addClass('x-hidden hide');
22204 if(Roo.isIE){ // fix IE 1px bogus margin
22205 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22209 this.frameId = Roo.id();
22213 var iframe = this.owner.wrap.createChild({
22215 cls: 'form-control', // bootstrap..
22217 name: this.frameId,
22218 frameBorder : 'no',
22219 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22224 this.iframe = iframe.dom;
22226 this.assignDocWin();
22228 this.doc.designMode = 'on';
22231 this.doc.write(this.getDocMarkup());
22235 var task = { // must defer to wait for browser to be ready
22237 //console.log("run task?" + this.doc.readyState);
22238 this.assignDocWin();
22239 if(this.doc.body || this.doc.readyState == 'complete'){
22241 this.doc.designMode="on";
22245 Roo.TaskMgr.stop(task);
22246 this.initEditor.defer(10, this);
22253 Roo.TaskMgr.start(task);
22258 onResize : function(w, h)
22260 Roo.log('resize: ' +w + ',' + h );
22261 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22265 if(typeof w == 'number'){
22267 this.iframe.style.width = w + 'px';
22269 if(typeof h == 'number'){
22271 this.iframe.style.height = h + 'px';
22273 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22280 * Toggles the editor between standard and source edit mode.
22281 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22283 toggleSourceEdit : function(sourceEditMode){
22285 this.sourceEditMode = sourceEditMode === true;
22287 if(this.sourceEditMode){
22289 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22292 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22293 //this.iframe.className = '';
22296 //this.setSize(this.owner.wrap.getSize());
22297 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22304 * Protected method that will not generally be called directly. If you need/want
22305 * custom HTML cleanup, this is the method you should override.
22306 * @param {String} html The HTML to be cleaned
22307 * return {String} The cleaned HTML
22309 cleanHtml : function(html){
22310 html = String(html);
22311 if(html.length > 5){
22312 if(Roo.isSafari){ // strip safari nonsense
22313 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22316 if(html == ' '){
22323 * HTML Editor -> Textarea
22324 * Protected method that will not generally be called directly. Syncs the contents
22325 * of the editor iframe with the textarea.
22327 syncValue : function(){
22328 if(this.initialized){
22329 var bd = (this.doc.body || this.doc.documentElement);
22330 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22331 var html = bd.innerHTML;
22333 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22334 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22336 html = '<div style="'+m[0]+'">' + html + '</div>';
22339 html = this.cleanHtml(html);
22340 // fix up the special chars.. normaly like back quotes in word...
22341 // however we do not want to do this with chinese..
22342 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22343 var cc = b.charCodeAt();
22345 (cc >= 0x4E00 && cc < 0xA000 ) ||
22346 (cc >= 0x3400 && cc < 0x4E00 ) ||
22347 (cc >= 0xf900 && cc < 0xfb00 )
22353 if(this.owner.fireEvent('beforesync', this, html) !== false){
22354 this.el.dom.value = html;
22355 this.owner.fireEvent('sync', this, html);
22361 * Protected method that will not generally be called directly. Pushes the value of the textarea
22362 * into the iframe editor.
22364 pushValue : function(){
22365 if(this.initialized){
22366 var v = this.el.dom.value.trim();
22368 // if(v.length < 1){
22372 if(this.owner.fireEvent('beforepush', this, v) !== false){
22373 var d = (this.doc.body || this.doc.documentElement);
22375 this.cleanUpPaste();
22376 this.el.dom.value = d.innerHTML;
22377 this.owner.fireEvent('push', this, v);
22383 deferFocus : function(){
22384 this.focus.defer(10, this);
22388 focus : function(){
22389 if(this.win && !this.sourceEditMode){
22396 assignDocWin: function()
22398 var iframe = this.iframe;
22401 this.doc = iframe.contentWindow.document;
22402 this.win = iframe.contentWindow;
22404 // if (!Roo.get(this.frameId)) {
22407 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22408 // this.win = Roo.get(this.frameId).dom.contentWindow;
22410 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22414 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22415 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22420 initEditor : function(){
22421 //console.log("INIT EDITOR");
22422 this.assignDocWin();
22426 this.doc.designMode="on";
22428 this.doc.write(this.getDocMarkup());
22431 var dbody = (this.doc.body || this.doc.documentElement);
22432 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22433 // this copies styles from the containing element into thsi one..
22434 // not sure why we need all of this..
22435 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22437 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22438 //ss['background-attachment'] = 'fixed'; // w3c
22439 dbody.bgProperties = 'fixed'; // ie
22440 //Roo.DomHelper.applyStyles(dbody, ss);
22441 Roo.EventManager.on(this.doc, {
22442 //'mousedown': this.onEditorEvent,
22443 'mouseup': this.onEditorEvent,
22444 'dblclick': this.onEditorEvent,
22445 'click': this.onEditorEvent,
22446 'keyup': this.onEditorEvent,
22451 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22453 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22454 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22456 this.initialized = true;
22458 this.owner.fireEvent('initialize', this);
22463 onDestroy : function(){
22469 //for (var i =0; i < this.toolbars.length;i++) {
22470 // // fixme - ask toolbars for heights?
22471 // this.toolbars[i].onDestroy();
22474 //this.wrap.dom.innerHTML = '';
22475 //this.wrap.remove();
22480 onFirstFocus : function(){
22482 this.assignDocWin();
22485 this.activated = true;
22488 if(Roo.isGecko){ // prevent silly gecko errors
22490 var s = this.win.getSelection();
22491 if(!s.focusNode || s.focusNode.nodeType != 3){
22492 var r = s.getRangeAt(0);
22493 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22498 this.execCmd('useCSS', true);
22499 this.execCmd('styleWithCSS', false);
22502 this.owner.fireEvent('activate', this);
22506 adjustFont: function(btn){
22507 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22508 //if(Roo.isSafari){ // safari
22511 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22512 if(Roo.isSafari){ // safari
22513 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22514 v = (v < 10) ? 10 : v;
22515 v = (v > 48) ? 48 : v;
22516 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22521 v = Math.max(1, v+adjust);
22523 this.execCmd('FontSize', v );
22526 onEditorEvent : function(e)
22528 this.owner.fireEvent('editorevent', this, e);
22529 // this.updateToolbar();
22530 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22533 insertTag : function(tg)
22535 // could be a bit smarter... -> wrap the current selected tRoo..
22536 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22538 range = this.createRange(this.getSelection());
22539 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22540 wrappingNode.appendChild(range.extractContents());
22541 range.insertNode(wrappingNode);
22548 this.execCmd("formatblock", tg);
22552 insertText : function(txt)
22556 var range = this.createRange();
22557 range.deleteContents();
22558 //alert(Sender.getAttribute('label'));
22560 range.insertNode(this.doc.createTextNode(txt));
22566 * Executes a Midas editor command on the editor document and performs necessary focus and
22567 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22568 * @param {String} cmd The Midas command
22569 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22571 relayCmd : function(cmd, value){
22573 this.execCmd(cmd, value);
22574 this.owner.fireEvent('editorevent', this);
22575 //this.updateToolbar();
22576 this.owner.deferFocus();
22580 * Executes a Midas editor command directly on the editor document.
22581 * For visual commands, you should use {@link #relayCmd} instead.
22582 * <b>This should only be called after the editor is initialized.</b>
22583 * @param {String} cmd The Midas command
22584 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22586 execCmd : function(cmd, value){
22587 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22594 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22596 * @param {String} text | dom node..
22598 insertAtCursor : function(text)
22601 if(!this.activated){
22607 var r = this.doc.selection.createRange();
22618 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22622 // from jquery ui (MIT licenced)
22624 var win = this.win;
22626 if (win.getSelection && win.getSelection().getRangeAt) {
22627 range = win.getSelection().getRangeAt(0);
22628 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22629 range.insertNode(node);
22630 } else if (win.document.selection && win.document.selection.createRange) {
22631 // no firefox support
22632 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22633 win.document.selection.createRange().pasteHTML(txt);
22635 // no firefox support
22636 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22637 this.execCmd('InsertHTML', txt);
22646 mozKeyPress : function(e){
22648 var c = e.getCharCode(), cmd;
22651 c = String.fromCharCode(c).toLowerCase();
22665 this.cleanUpPaste.defer(100, this);
22673 e.preventDefault();
22681 fixKeys : function(){ // load time branching for fastest keydown performance
22683 return function(e){
22684 var k = e.getKey(), r;
22687 r = this.doc.selection.createRange();
22690 r.pasteHTML('    ');
22697 r = this.doc.selection.createRange();
22699 var target = r.parentElement();
22700 if(!target || target.tagName.toLowerCase() != 'li'){
22702 r.pasteHTML('<br />');
22708 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22709 this.cleanUpPaste.defer(100, this);
22715 }else if(Roo.isOpera){
22716 return function(e){
22717 var k = e.getKey();
22721 this.execCmd('InsertHTML','    ');
22724 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22725 this.cleanUpPaste.defer(100, this);
22730 }else if(Roo.isSafari){
22731 return function(e){
22732 var k = e.getKey();
22736 this.execCmd('InsertText','\t');
22740 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22741 this.cleanUpPaste.defer(100, this);
22749 getAllAncestors: function()
22751 var p = this.getSelectedNode();
22754 a.push(p); // push blank onto stack..
22755 p = this.getParentElement();
22759 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22763 a.push(this.doc.body);
22767 lastSelNode : false,
22770 getSelection : function()
22772 this.assignDocWin();
22773 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22776 getSelectedNode: function()
22778 // this may only work on Gecko!!!
22780 // should we cache this!!!!
22785 var range = this.createRange(this.getSelection()).cloneRange();
22788 var parent = range.parentElement();
22790 var testRange = range.duplicate();
22791 testRange.moveToElementText(parent);
22792 if (testRange.inRange(range)) {
22795 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22798 parent = parent.parentElement;
22803 // is ancestor a text element.
22804 var ac = range.commonAncestorContainer;
22805 if (ac.nodeType == 3) {
22806 ac = ac.parentNode;
22809 var ar = ac.childNodes;
22812 var other_nodes = [];
22813 var has_other_nodes = false;
22814 for (var i=0;i<ar.length;i++) {
22815 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22818 // fullly contained node.
22820 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22825 // probably selected..
22826 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22827 other_nodes.push(ar[i]);
22831 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22836 has_other_nodes = true;
22838 if (!nodes.length && other_nodes.length) {
22839 nodes= other_nodes;
22841 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22847 createRange: function(sel)
22849 // this has strange effects when using with
22850 // top toolbar - not sure if it's a great idea.
22851 //this.editor.contentWindow.focus();
22852 if (typeof sel != "undefined") {
22854 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22856 return this.doc.createRange();
22859 return this.doc.createRange();
22862 getParentElement: function()
22865 this.assignDocWin();
22866 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22868 var range = this.createRange(sel);
22871 var p = range.commonAncestorContainer;
22872 while (p.nodeType == 3) { // text node
22883 * Range intersection.. the hard stuff...
22887 * [ -- selected range --- ]
22891 * if end is before start or hits it. fail.
22892 * if start is after end or hits it fail.
22894 * if either hits (but other is outside. - then it's not
22900 // @see http://www.thismuchiknow.co.uk/?p=64.
22901 rangeIntersectsNode : function(range, node)
22903 var nodeRange = node.ownerDocument.createRange();
22905 nodeRange.selectNode(node);
22907 nodeRange.selectNodeContents(node);
22910 var rangeStartRange = range.cloneRange();
22911 rangeStartRange.collapse(true);
22913 var rangeEndRange = range.cloneRange();
22914 rangeEndRange.collapse(false);
22916 var nodeStartRange = nodeRange.cloneRange();
22917 nodeStartRange.collapse(true);
22919 var nodeEndRange = nodeRange.cloneRange();
22920 nodeEndRange.collapse(false);
22922 return rangeStartRange.compareBoundaryPoints(
22923 Range.START_TO_START, nodeEndRange) == -1 &&
22924 rangeEndRange.compareBoundaryPoints(
22925 Range.START_TO_START, nodeStartRange) == 1;
22929 rangeCompareNode : function(range, node)
22931 var nodeRange = node.ownerDocument.createRange();
22933 nodeRange.selectNode(node);
22935 nodeRange.selectNodeContents(node);
22939 range.collapse(true);
22941 nodeRange.collapse(true);
22943 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22944 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22946 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22948 var nodeIsBefore = ss == 1;
22949 var nodeIsAfter = ee == -1;
22951 if (nodeIsBefore && nodeIsAfter) {
22954 if (!nodeIsBefore && nodeIsAfter) {
22955 return 1; //right trailed.
22958 if (nodeIsBefore && !nodeIsAfter) {
22959 return 2; // left trailed.
22965 // private? - in a new class?
22966 cleanUpPaste : function()
22968 // cleans up the whole document..
22969 Roo.log('cleanuppaste');
22971 this.cleanUpChildren(this.doc.body);
22972 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22973 if (clean != this.doc.body.innerHTML) {
22974 this.doc.body.innerHTML = clean;
22979 cleanWordChars : function(input) {// change the chars to hex code
22980 var he = Roo.HtmlEditorCore;
22982 var output = input;
22983 Roo.each(he.swapCodes, function(sw) {
22984 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22986 output = output.replace(swapper, sw[1]);
22993 cleanUpChildren : function (n)
22995 if (!n.childNodes.length) {
22998 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22999 this.cleanUpChild(n.childNodes[i]);
23006 cleanUpChild : function (node)
23009 //console.log(node);
23010 if (node.nodeName == "#text") {
23011 // clean up silly Windows -- stuff?
23014 if (node.nodeName == "#comment") {
23015 node.parentNode.removeChild(node);
23016 // clean up silly Windows -- stuff?
23019 var lcname = node.tagName.toLowerCase();
23020 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23021 // whitelist of tags..
23023 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23025 node.parentNode.removeChild(node);
23030 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23032 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23033 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23035 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23036 // remove_keep_children = true;
23039 if (remove_keep_children) {
23040 this.cleanUpChildren(node);
23041 // inserts everything just before this node...
23042 while (node.childNodes.length) {
23043 var cn = node.childNodes[0];
23044 node.removeChild(cn);
23045 node.parentNode.insertBefore(cn, node);
23047 node.parentNode.removeChild(node);
23051 if (!node.attributes || !node.attributes.length) {
23052 this.cleanUpChildren(node);
23056 function cleanAttr(n,v)
23059 if (v.match(/^\./) || v.match(/^\//)) {
23062 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23065 if (v.match(/^#/)) {
23068 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23069 node.removeAttribute(n);
23073 var cwhite = this.cwhite;
23074 var cblack = this.cblack;
23076 function cleanStyle(n,v)
23078 if (v.match(/expression/)) { //XSS?? should we even bother..
23079 node.removeAttribute(n);
23083 var parts = v.split(/;/);
23086 Roo.each(parts, function(p) {
23087 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23091 var l = p.split(':').shift().replace(/\s+/g,'');
23092 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23094 if ( cwhite.length && cblack.indexOf(l) > -1) {
23095 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23096 //node.removeAttribute(n);
23100 // only allow 'c whitelisted system attributes'
23101 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23102 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23103 //node.removeAttribute(n);
23113 if (clean.length) {
23114 node.setAttribute(n, clean.join(';'));
23116 node.removeAttribute(n);
23122 for (var i = node.attributes.length-1; i > -1 ; i--) {
23123 var a = node.attributes[i];
23126 if (a.name.toLowerCase().substr(0,2)=='on') {
23127 node.removeAttribute(a.name);
23130 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23131 node.removeAttribute(a.name);
23134 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23135 cleanAttr(a.name,a.value); // fixme..
23138 if (a.name == 'style') {
23139 cleanStyle(a.name,a.value);
23142 /// clean up MS crap..
23143 // tecnically this should be a list of valid class'es..
23146 if (a.name == 'class') {
23147 if (a.value.match(/^Mso/)) {
23148 node.className = '';
23151 if (a.value.match(/^body$/)) {
23152 node.className = '';
23163 this.cleanUpChildren(node);
23169 * Clean up MS wordisms...
23171 cleanWord : function(node)
23176 this.cleanWord(this.doc.body);
23179 if (node.nodeName == "#text") {
23180 // clean up silly Windows -- stuff?
23183 if (node.nodeName == "#comment") {
23184 node.parentNode.removeChild(node);
23185 // clean up silly Windows -- stuff?
23189 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23190 node.parentNode.removeChild(node);
23194 // remove - but keep children..
23195 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23196 while (node.childNodes.length) {
23197 var cn = node.childNodes[0];
23198 node.removeChild(cn);
23199 node.parentNode.insertBefore(cn, node);
23201 node.parentNode.removeChild(node);
23202 this.iterateChildren(node, this.cleanWord);
23206 if (node.className.length) {
23208 var cn = node.className.split(/\W+/);
23210 Roo.each(cn, function(cls) {
23211 if (cls.match(/Mso[a-zA-Z]+/)) {
23216 node.className = cna.length ? cna.join(' ') : '';
23218 node.removeAttribute("class");
23222 if (node.hasAttribute("lang")) {
23223 node.removeAttribute("lang");
23226 if (node.hasAttribute("style")) {
23228 var styles = node.getAttribute("style").split(";");
23230 Roo.each(styles, function(s) {
23231 if (!s.match(/:/)) {
23234 var kv = s.split(":");
23235 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23238 // what ever is left... we allow.
23241 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23242 if (!nstyle.length) {
23243 node.removeAttribute('style');
23246 this.iterateChildren(node, this.cleanWord);
23252 * iterateChildren of a Node, calling fn each time, using this as the scole..
23253 * @param {DomNode} node node to iterate children of.
23254 * @param {Function} fn method of this class to call on each item.
23256 iterateChildren : function(node, fn)
23258 if (!node.childNodes.length) {
23261 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23262 fn.call(this, node.childNodes[i])
23268 * cleanTableWidths.
23270 * Quite often pasting from word etc.. results in tables with column and widths.
23271 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23274 cleanTableWidths : function(node)
23279 this.cleanTableWidths(this.doc.body);
23284 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23287 Roo.log(node.tagName);
23288 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23289 this.iterateChildren(node, this.cleanTableWidths);
23292 if (node.hasAttribute('width')) {
23293 node.removeAttribute('width');
23297 if (node.hasAttribute("style")) {
23300 var styles = node.getAttribute("style").split(";");
23302 Roo.each(styles, function(s) {
23303 if (!s.match(/:/)) {
23306 var kv = s.split(":");
23307 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23310 // what ever is left... we allow.
23313 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23314 if (!nstyle.length) {
23315 node.removeAttribute('style');
23319 this.iterateChildren(node, this.cleanTableWidths);
23327 domToHTML : function(currentElement, depth, nopadtext) {
23329 depth = depth || 0;
23330 nopadtext = nopadtext || false;
23332 if (!currentElement) {
23333 return this.domToHTML(this.doc.body);
23336 //Roo.log(currentElement);
23338 var allText = false;
23339 var nodeName = currentElement.nodeName;
23340 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23342 if (nodeName == '#text') {
23344 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23349 if (nodeName != 'BODY') {
23352 // Prints the node tagName, such as <A>, <IMG>, etc
23355 for(i = 0; i < currentElement.attributes.length;i++) {
23357 var aname = currentElement.attributes.item(i).name;
23358 if (!currentElement.attributes.item(i).value.length) {
23361 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23364 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23373 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23376 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23381 // Traverse the tree
23383 var currentElementChild = currentElement.childNodes.item(i);
23384 var allText = true;
23385 var innerHTML = '';
23387 while (currentElementChild) {
23388 // Formatting code (indent the tree so it looks nice on the screen)
23389 var nopad = nopadtext;
23390 if (lastnode == 'SPAN') {
23394 if (currentElementChild.nodeName == '#text') {
23395 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23396 toadd = nopadtext ? toadd : toadd.trim();
23397 if (!nopad && toadd.length > 80) {
23398 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23400 innerHTML += toadd;
23403 currentElementChild = currentElement.childNodes.item(i);
23409 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23411 // Recursively traverse the tree structure of the child node
23412 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23413 lastnode = currentElementChild.nodeName;
23415 currentElementChild=currentElement.childNodes.item(i);
23421 // The remaining code is mostly for formatting the tree
23422 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23427 ret+= "</"+tagName+">";
23433 applyBlacklists : function()
23435 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23436 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23440 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23441 if (b.indexOf(tag) > -1) {
23444 this.white.push(tag);
23448 Roo.each(w, function(tag) {
23449 if (b.indexOf(tag) > -1) {
23452 if (this.white.indexOf(tag) > -1) {
23455 this.white.push(tag);
23460 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23461 if (w.indexOf(tag) > -1) {
23464 this.black.push(tag);
23468 Roo.each(b, function(tag) {
23469 if (w.indexOf(tag) > -1) {
23472 if (this.black.indexOf(tag) > -1) {
23475 this.black.push(tag);
23480 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23481 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23485 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23486 if (b.indexOf(tag) > -1) {
23489 this.cwhite.push(tag);
23493 Roo.each(w, function(tag) {
23494 if (b.indexOf(tag) > -1) {
23497 if (this.cwhite.indexOf(tag) > -1) {
23500 this.cwhite.push(tag);
23505 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23506 if (w.indexOf(tag) > -1) {
23509 this.cblack.push(tag);
23513 Roo.each(b, function(tag) {
23514 if (w.indexOf(tag) > -1) {
23517 if (this.cblack.indexOf(tag) > -1) {
23520 this.cblack.push(tag);
23525 setStylesheets : function(stylesheets)
23527 if(typeof(stylesheets) == 'string'){
23528 Roo.get(this.iframe.contentDocument.head).createChild({
23530 rel : 'stylesheet',
23539 Roo.each(stylesheets, function(s) {
23544 Roo.get(_this.iframe.contentDocument.head).createChild({
23546 rel : 'stylesheet',
23555 removeStylesheets : function()
23559 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23564 setStyle : function(style)
23566 Roo.get(this.iframe.contentDocument.head).createChild({
23575 // hide stuff that is not compatible
23589 * @event specialkey
23593 * @cfg {String} fieldClass @hide
23596 * @cfg {String} focusClass @hide
23599 * @cfg {String} autoCreate @hide
23602 * @cfg {String} inputType @hide
23605 * @cfg {String} invalidClass @hide
23608 * @cfg {String} invalidText @hide
23611 * @cfg {String} msgFx @hide
23614 * @cfg {String} validateOnBlur @hide
23618 Roo.HtmlEditorCore.white = [
23619 'area', 'br', 'img', 'input', 'hr', 'wbr',
23621 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23622 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23623 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23624 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23625 'table', 'ul', 'xmp',
23627 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23630 'dir', 'menu', 'ol', 'ul', 'dl',
23636 Roo.HtmlEditorCore.black = [
23637 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23639 'base', 'basefont', 'bgsound', 'blink', 'body',
23640 'frame', 'frameset', 'head', 'html', 'ilayer',
23641 'iframe', 'layer', 'link', 'meta', 'object',
23642 'script', 'style' ,'title', 'xml' // clean later..
23644 Roo.HtmlEditorCore.clean = [
23645 'script', 'style', 'title', 'xml'
23647 Roo.HtmlEditorCore.remove = [
23652 Roo.HtmlEditorCore.ablack = [
23656 Roo.HtmlEditorCore.aclean = [
23657 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23661 Roo.HtmlEditorCore.pwhite= [
23662 'http', 'https', 'mailto'
23665 // white listed style attributes.
23666 Roo.HtmlEditorCore.cwhite= [
23667 // 'text-align', /// default is to allow most things..
23673 // black listed style attributes.
23674 Roo.HtmlEditorCore.cblack= [
23675 // 'font-size' -- this can be set by the project
23679 Roo.HtmlEditorCore.swapCodes =[
23698 * @class Roo.bootstrap.HtmlEditor
23699 * @extends Roo.bootstrap.TextArea
23700 * Bootstrap HtmlEditor class
23703 * Create a new HtmlEditor
23704 * @param {Object} config The config object
23707 Roo.bootstrap.HtmlEditor = function(config){
23708 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23709 if (!this.toolbars) {
23710 this.toolbars = [];
23713 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23716 * @event initialize
23717 * Fires when the editor is fully initialized (including the iframe)
23718 * @param {HtmlEditor} this
23723 * Fires when the editor is first receives the focus. Any insertion must wait
23724 * until after this event.
23725 * @param {HtmlEditor} this
23729 * @event beforesync
23730 * Fires before the textarea is updated with content from the editor iframe. Return false
23731 * to cancel the sync.
23732 * @param {HtmlEditor} this
23733 * @param {String} html
23737 * @event beforepush
23738 * Fires before the iframe editor is updated with content from the textarea. Return false
23739 * to cancel the push.
23740 * @param {HtmlEditor} this
23741 * @param {String} html
23746 * Fires when the textarea is updated with content from the editor iframe.
23747 * @param {HtmlEditor} this
23748 * @param {String} html
23753 * Fires when the iframe editor is updated with content from the textarea.
23754 * @param {HtmlEditor} this
23755 * @param {String} html
23759 * @event editmodechange
23760 * Fires when the editor switches edit modes
23761 * @param {HtmlEditor} this
23762 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23764 editmodechange: true,
23766 * @event editorevent
23767 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23768 * @param {HtmlEditor} this
23772 * @event firstfocus
23773 * Fires when on first focus - needed by toolbars..
23774 * @param {HtmlEditor} this
23779 * Auto save the htmlEditor value as a file into Events
23780 * @param {HtmlEditor} this
23784 * @event savedpreview
23785 * preview the saved version of htmlEditor
23786 * @param {HtmlEditor} this
23793 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23797 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23802 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23807 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23812 * @cfg {Number} height (in pixels)
23816 * @cfg {Number} width (in pixels)
23821 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23824 stylesheets: false,
23829 // private properties
23830 validationEvent : false,
23832 initialized : false,
23835 onFocus : Roo.emptyFn,
23837 hideMode:'offsets',
23839 tbContainer : false,
23843 toolbarContainer :function() {
23844 return this.wrap.select('.x-html-editor-tb',true).first();
23848 * Protected method that will not generally be called directly. It
23849 * is called when the editor creates its toolbar. Override this method if you need to
23850 * add custom toolbar buttons.
23851 * @param {HtmlEditor} editor
23853 createToolbar : function(){
23854 Roo.log('renewing');
23855 Roo.log("create toolbars");
23857 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23858 this.toolbars[0].render(this.toolbarContainer());
23862 // if (!editor.toolbars || !editor.toolbars.length) {
23863 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23866 // for (var i =0 ; i < editor.toolbars.length;i++) {
23867 // editor.toolbars[i] = Roo.factory(
23868 // typeof(editor.toolbars[i]) == 'string' ?
23869 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23870 // Roo.bootstrap.HtmlEditor);
23871 // editor.toolbars[i].init(editor);
23877 onRender : function(ct, position)
23879 // Roo.log("Call onRender: " + this.xtype);
23881 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23883 this.wrap = this.inputEl().wrap({
23884 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23887 this.editorcore.onRender(ct, position);
23889 if (this.resizable) {
23890 this.resizeEl = new Roo.Resizable(this.wrap, {
23894 minHeight : this.height,
23895 height: this.height,
23896 handles : this.resizable,
23899 resize : function(r, w, h) {
23900 _t.onResize(w,h); // -something
23906 this.createToolbar(this);
23909 if(!this.width && this.resizable){
23910 this.setSize(this.wrap.getSize());
23912 if (this.resizeEl) {
23913 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23914 // should trigger onReize..
23920 onResize : function(w, h)
23922 Roo.log('resize: ' +w + ',' + h );
23923 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23927 if(this.inputEl() ){
23928 if(typeof w == 'number'){
23929 var aw = w - this.wrap.getFrameWidth('lr');
23930 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23933 if(typeof h == 'number'){
23934 var tbh = -11; // fixme it needs to tool bar size!
23935 for (var i =0; i < this.toolbars.length;i++) {
23936 // fixme - ask toolbars for heights?
23937 tbh += this.toolbars[i].el.getHeight();
23938 //if (this.toolbars[i].footer) {
23939 // tbh += this.toolbars[i].footer.el.getHeight();
23947 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23948 ah -= 5; // knock a few pixes off for look..
23949 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23953 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23954 this.editorcore.onResize(ew,eh);
23959 * Toggles the editor between standard and source edit mode.
23960 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23962 toggleSourceEdit : function(sourceEditMode)
23964 this.editorcore.toggleSourceEdit(sourceEditMode);
23966 if(this.editorcore.sourceEditMode){
23967 Roo.log('editor - showing textarea');
23970 // Roo.log(this.syncValue());
23972 this.inputEl().removeClass(['hide', 'x-hidden']);
23973 this.inputEl().dom.removeAttribute('tabIndex');
23974 this.inputEl().focus();
23976 Roo.log('editor - hiding textarea');
23978 // Roo.log(this.pushValue());
23981 this.inputEl().addClass(['hide', 'x-hidden']);
23982 this.inputEl().dom.setAttribute('tabIndex', -1);
23983 //this.deferFocus();
23986 if(this.resizable){
23987 this.setSize(this.wrap.getSize());
23990 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23993 // private (for BoxComponent)
23994 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23996 // private (for BoxComponent)
23997 getResizeEl : function(){
24001 // private (for BoxComponent)
24002 getPositionEl : function(){
24007 initEvents : function(){
24008 this.originalValue = this.getValue();
24012 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24015 // markInvalid : Roo.emptyFn,
24017 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24020 // clearInvalid : Roo.emptyFn,
24022 setValue : function(v){
24023 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24024 this.editorcore.pushValue();
24029 deferFocus : function(){
24030 this.focus.defer(10, this);
24034 focus : function(){
24035 this.editorcore.focus();
24041 onDestroy : function(){
24047 for (var i =0; i < this.toolbars.length;i++) {
24048 // fixme - ask toolbars for heights?
24049 this.toolbars[i].onDestroy();
24052 this.wrap.dom.innerHTML = '';
24053 this.wrap.remove();
24058 onFirstFocus : function(){
24059 //Roo.log("onFirstFocus");
24060 this.editorcore.onFirstFocus();
24061 for (var i =0; i < this.toolbars.length;i++) {
24062 this.toolbars[i].onFirstFocus();
24068 syncValue : function()
24070 this.editorcore.syncValue();
24073 pushValue : function()
24075 this.editorcore.pushValue();
24079 // hide stuff that is not compatible
24093 * @event specialkey
24097 * @cfg {String} fieldClass @hide
24100 * @cfg {String} focusClass @hide
24103 * @cfg {String} autoCreate @hide
24106 * @cfg {String} inputType @hide
24110 * @cfg {String} invalidText @hide
24113 * @cfg {String} msgFx @hide
24116 * @cfg {String} validateOnBlur @hide
24125 Roo.namespace('Roo.bootstrap.htmleditor');
24127 * @class Roo.bootstrap.HtmlEditorToolbar1
24133 new Roo.bootstrap.HtmlEditor({
24136 new Roo.bootstrap.HtmlEditorToolbar1({
24137 disable : { fonts: 1 , format: 1, ..., ... , ...],
24143 * @cfg {Object} disable List of elements to disable..
24144 * @cfg {Array} btns List of additional buttons.
24148 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24151 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24154 Roo.apply(this, config);
24156 // default disabled, based on 'good practice'..
24157 this.disable = this.disable || {};
24158 Roo.applyIf(this.disable, {
24161 specialElements : true
24163 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24165 this.editor = config.editor;
24166 this.editorcore = config.editor.editorcore;
24168 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24170 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24171 // dont call parent... till later.
24173 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24178 editorcore : false,
24183 "h1","h2","h3","h4","h5","h6",
24185 "abbr", "acronym", "address", "cite", "samp", "var",
24189 onRender : function(ct, position)
24191 // Roo.log("Call onRender: " + this.xtype);
24193 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24195 this.el.dom.style.marginBottom = '0';
24197 var editorcore = this.editorcore;
24198 var editor= this.editor;
24201 var btn = function(id,cmd , toggle, handler, html){
24203 var event = toggle ? 'toggle' : 'click';
24208 xns: Roo.bootstrap,
24212 enableToggle:toggle !== false,
24214 pressed : toggle ? false : null,
24217 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24218 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24224 // var cb_box = function...
24229 xns: Roo.bootstrap,
24234 xns: Roo.bootstrap,
24238 Roo.each(this.formats, function(f) {
24239 style.menu.items.push({
24241 xns: Roo.bootstrap,
24242 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24247 editorcore.insertTag(this.tagname);
24254 children.push(style);
24256 btn('bold',false,true);
24257 btn('italic',false,true);
24258 btn('align-left', 'justifyleft',true);
24259 btn('align-center', 'justifycenter',true);
24260 btn('align-right' , 'justifyright',true);
24261 btn('link', false, false, function(btn) {
24262 //Roo.log("create link?");
24263 var url = prompt(this.createLinkText, this.defaultLinkValue);
24264 if(url && url != 'http:/'+'/'){
24265 this.editorcore.relayCmd('createlink', url);
24268 btn('list','insertunorderedlist',true);
24269 btn('pencil', false,true, function(btn){
24271 this.toggleSourceEdit(btn.pressed);
24274 if (this.editor.btns.length > 0) {
24275 for (var i = 0; i<this.editor.btns.length; i++) {
24276 children.push(this.editor.btns[i]);
24284 xns: Roo.bootstrap,
24289 xns: Roo.bootstrap,
24294 cog.menu.items.push({
24296 xns: Roo.bootstrap,
24297 html : Clean styles,
24302 editorcore.insertTag(this.tagname);
24311 this.xtype = 'NavSimplebar';
24313 for(var i=0;i< children.length;i++) {
24315 this.buttons.add(this.addxtypeChild(children[i]));
24319 editor.on('editorevent', this.updateToolbar, this);
24321 onBtnClick : function(id)
24323 this.editorcore.relayCmd(id);
24324 this.editorcore.focus();
24328 * Protected method that will not generally be called directly. It triggers
24329 * a toolbar update by reading the markup state of the current selection in the editor.
24331 updateToolbar: function(){
24333 if(!this.editorcore.activated){
24334 this.editor.onFirstFocus(); // is this neeed?
24338 var btns = this.buttons;
24339 var doc = this.editorcore.doc;
24340 btns.get('bold').setActive(doc.queryCommandState('bold'));
24341 btns.get('italic').setActive(doc.queryCommandState('italic'));
24342 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24344 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24345 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24346 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24348 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24349 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24352 var ans = this.editorcore.getAllAncestors();
24353 if (this.formatCombo) {
24356 var store = this.formatCombo.store;
24357 this.formatCombo.setValue("");
24358 for (var i =0; i < ans.length;i++) {
24359 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24361 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24369 // hides menus... - so this cant be on a menu...
24370 Roo.bootstrap.MenuMgr.hideAll();
24372 Roo.bootstrap.MenuMgr.hideAll();
24373 //this.editorsyncValue();
24375 onFirstFocus: function() {
24376 this.buttons.each(function(item){
24380 toggleSourceEdit : function(sourceEditMode){
24383 if(sourceEditMode){
24384 Roo.log("disabling buttons");
24385 this.buttons.each( function(item){
24386 if(item.cmd != 'pencil'){
24392 Roo.log("enabling buttons");
24393 if(this.editorcore.initialized){
24394 this.buttons.each( function(item){
24400 Roo.log("calling toggole on editor");
24401 // tell the editor that it's been pressed..
24402 this.editor.toggleSourceEdit(sourceEditMode);
24412 * @class Roo.bootstrap.Table.AbstractSelectionModel
24413 * @extends Roo.util.Observable
24414 * Abstract base class for grid SelectionModels. It provides the interface that should be
24415 * implemented by descendant classes. This class should not be directly instantiated.
24418 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24419 this.locked = false;
24420 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24424 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24425 /** @ignore Called by the grid automatically. Do not call directly. */
24426 init : function(grid){
24432 * Locks the selections.
24435 this.locked = true;
24439 * Unlocks the selections.
24441 unlock : function(){
24442 this.locked = false;
24446 * Returns true if the selections are locked.
24447 * @return {Boolean}
24449 isLocked : function(){
24450 return this.locked;
24454 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24455 * @class Roo.bootstrap.Table.RowSelectionModel
24456 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24457 * It supports multiple selections and keyboard selection/navigation.
24459 * @param {Object} config
24462 Roo.bootstrap.Table.RowSelectionModel = function(config){
24463 Roo.apply(this, config);
24464 this.selections = new Roo.util.MixedCollection(false, function(o){
24469 this.lastActive = false;
24473 * @event selectionchange
24474 * Fires when the selection changes
24475 * @param {SelectionModel} this
24477 "selectionchange" : true,
24479 * @event afterselectionchange
24480 * Fires after the selection changes (eg. by key press or clicking)
24481 * @param {SelectionModel} this
24483 "afterselectionchange" : true,
24485 * @event beforerowselect
24486 * Fires when a row is selected being selected, return false to cancel.
24487 * @param {SelectionModel} this
24488 * @param {Number} rowIndex The selected index
24489 * @param {Boolean} keepExisting False if other selections will be cleared
24491 "beforerowselect" : true,
24494 * Fires when a row is selected.
24495 * @param {SelectionModel} this
24496 * @param {Number} rowIndex The selected index
24497 * @param {Roo.data.Record} r The record
24499 "rowselect" : true,
24501 * @event rowdeselect
24502 * Fires when a row is deselected.
24503 * @param {SelectionModel} this
24504 * @param {Number} rowIndex The selected index
24506 "rowdeselect" : true
24508 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24509 this.locked = false;
24512 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24514 * @cfg {Boolean} singleSelect
24515 * True to allow selection of only one row at a time (defaults to false)
24517 singleSelect : false,
24520 initEvents : function()
24523 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24524 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24525 //}else{ // allow click to work like normal
24526 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24528 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24529 this.grid.on("rowclick", this.handleMouseDown, this);
24531 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24532 "up" : function(e){
24534 this.selectPrevious(e.shiftKey);
24535 }else if(this.last !== false && this.lastActive !== false){
24536 var last = this.last;
24537 this.selectRange(this.last, this.lastActive-1);
24538 this.grid.getView().focusRow(this.lastActive);
24539 if(last !== false){
24543 this.selectFirstRow();
24545 this.fireEvent("afterselectionchange", this);
24547 "down" : function(e){
24549 this.selectNext(e.shiftKey);
24550 }else if(this.last !== false && this.lastActive !== false){
24551 var last = this.last;
24552 this.selectRange(this.last, this.lastActive+1);
24553 this.grid.getView().focusRow(this.lastActive);
24554 if(last !== false){
24558 this.selectFirstRow();
24560 this.fireEvent("afterselectionchange", this);
24564 this.grid.store.on('load', function(){
24565 this.selections.clear();
24568 var view = this.grid.view;
24569 view.on("refresh", this.onRefresh, this);
24570 view.on("rowupdated", this.onRowUpdated, this);
24571 view.on("rowremoved", this.onRemove, this);
24576 onRefresh : function()
24578 var ds = this.grid.store, i, v = this.grid.view;
24579 var s = this.selections;
24580 s.each(function(r){
24581 if((i = ds.indexOfId(r.id)) != -1){
24590 onRemove : function(v, index, r){
24591 this.selections.remove(r);
24595 onRowUpdated : function(v, index, r){
24596 if(this.isSelected(r)){
24597 v.onRowSelect(index);
24603 * @param {Array} records The records to select
24604 * @param {Boolean} keepExisting (optional) True to keep existing selections
24606 selectRecords : function(records, keepExisting)
24609 this.clearSelections();
24611 var ds = this.grid.store;
24612 for(var i = 0, len = records.length; i < len; i++){
24613 this.selectRow(ds.indexOf(records[i]), true);
24618 * Gets the number of selected rows.
24621 getCount : function(){
24622 return this.selections.length;
24626 * Selects the first row in the grid.
24628 selectFirstRow : function(){
24633 * Select the last row.
24634 * @param {Boolean} keepExisting (optional) True to keep existing selections
24636 selectLastRow : function(keepExisting){
24637 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24638 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24642 * Selects the row immediately following the last selected row.
24643 * @param {Boolean} keepExisting (optional) True to keep existing selections
24645 selectNext : function(keepExisting)
24647 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24648 this.selectRow(this.last+1, keepExisting);
24649 this.grid.getView().focusRow(this.last);
24654 * Selects the row that precedes the last selected row.
24655 * @param {Boolean} keepExisting (optional) True to keep existing selections
24657 selectPrevious : function(keepExisting){
24659 this.selectRow(this.last-1, keepExisting);
24660 this.grid.getView().focusRow(this.last);
24665 * Returns the selected records
24666 * @return {Array} Array of selected records
24668 getSelections : function(){
24669 return [].concat(this.selections.items);
24673 * Returns the first selected record.
24676 getSelected : function(){
24677 return this.selections.itemAt(0);
24682 * Clears all selections.
24684 clearSelections : function(fast)
24690 var ds = this.grid.store;
24691 var s = this.selections;
24692 s.each(function(r){
24693 this.deselectRow(ds.indexOfId(r.id));
24697 this.selections.clear();
24704 * Selects all rows.
24706 selectAll : function(){
24710 this.selections.clear();
24711 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24712 this.selectRow(i, true);
24717 * Returns True if there is a selection.
24718 * @return {Boolean}
24720 hasSelection : function(){
24721 return this.selections.length > 0;
24725 * Returns True if the specified row is selected.
24726 * @param {Number/Record} record The record or index of the record to check
24727 * @return {Boolean}
24729 isSelected : function(index){
24730 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24731 return (r && this.selections.key(r.id) ? true : false);
24735 * Returns True if the specified record id is selected.
24736 * @param {String} id The id of record to check
24737 * @return {Boolean}
24739 isIdSelected : function(id){
24740 return (this.selections.key(id) ? true : false);
24745 handleMouseDBClick : function(e, t){
24749 handleMouseDown : function(e, t)
24751 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24752 if(this.isLocked() || rowIndex < 0 ){
24755 if(e.shiftKey && this.last !== false){
24756 var last = this.last;
24757 this.selectRange(last, rowIndex, e.ctrlKey);
24758 this.last = last; // reset the last
24762 var isSelected = this.isSelected(rowIndex);
24763 //Roo.log("select row:" + rowIndex);
24765 this.deselectRow(rowIndex);
24767 this.selectRow(rowIndex, true);
24771 if(e.button !== 0 && isSelected){
24772 alert('rowIndex 2: ' + rowIndex);
24773 view.focusRow(rowIndex);
24774 }else if(e.ctrlKey && isSelected){
24775 this.deselectRow(rowIndex);
24776 }else if(!isSelected){
24777 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24778 view.focusRow(rowIndex);
24782 this.fireEvent("afterselectionchange", this);
24785 handleDragableRowClick : function(grid, rowIndex, e)
24787 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24788 this.selectRow(rowIndex, false);
24789 grid.view.focusRow(rowIndex);
24790 this.fireEvent("afterselectionchange", this);
24795 * Selects multiple rows.
24796 * @param {Array} rows Array of the indexes of the row to select
24797 * @param {Boolean} keepExisting (optional) True to keep existing selections
24799 selectRows : function(rows, keepExisting){
24801 this.clearSelections();
24803 for(var i = 0, len = rows.length; i < len; i++){
24804 this.selectRow(rows[i], true);
24809 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24810 * @param {Number} startRow The index of the first row in the range
24811 * @param {Number} endRow The index of the last row in the range
24812 * @param {Boolean} keepExisting (optional) True to retain existing selections
24814 selectRange : function(startRow, endRow, keepExisting){
24819 this.clearSelections();
24821 if(startRow <= endRow){
24822 for(var i = startRow; i <= endRow; i++){
24823 this.selectRow(i, true);
24826 for(var i = startRow; i >= endRow; i--){
24827 this.selectRow(i, true);
24833 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24834 * @param {Number} startRow The index of the first row in the range
24835 * @param {Number} endRow The index of the last row in the range
24837 deselectRange : function(startRow, endRow, preventViewNotify){
24841 for(var i = startRow; i <= endRow; i++){
24842 this.deselectRow(i, preventViewNotify);
24848 * @param {Number} row The index of the row to select
24849 * @param {Boolean} keepExisting (optional) True to keep existing selections
24851 selectRow : function(index, keepExisting, preventViewNotify)
24853 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24856 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24857 if(!keepExisting || this.singleSelect){
24858 this.clearSelections();
24861 var r = this.grid.store.getAt(index);
24862 //console.log('selectRow - record id :' + r.id);
24864 this.selections.add(r);
24865 this.last = this.lastActive = index;
24866 if(!preventViewNotify){
24867 var proxy = new Roo.Element(
24868 this.grid.getRowDom(index)
24870 proxy.addClass('bg-info info');
24872 this.fireEvent("rowselect", this, index, r);
24873 this.fireEvent("selectionchange", this);
24879 * @param {Number} row The index of the row to deselect
24881 deselectRow : function(index, preventViewNotify)
24886 if(this.last == index){
24889 if(this.lastActive == index){
24890 this.lastActive = false;
24893 var r = this.grid.store.getAt(index);
24898 this.selections.remove(r);
24899 //.console.log('deselectRow - record id :' + r.id);
24900 if(!preventViewNotify){
24902 var proxy = new Roo.Element(
24903 this.grid.getRowDom(index)
24905 proxy.removeClass('bg-info info');
24907 this.fireEvent("rowdeselect", this, index);
24908 this.fireEvent("selectionchange", this);
24912 restoreLast : function(){
24914 this.last = this._last;
24919 acceptsNav : function(row, col, cm){
24920 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24924 onEditorKey : function(field, e){
24925 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24930 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24932 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24934 }else if(k == e.ENTER && !e.ctrlKey){
24938 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24940 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24942 }else if(k == e.ESC){
24946 g.startEditing(newCell[0], newCell[1]);
24952 * Ext JS Library 1.1.1
24953 * Copyright(c) 2006-2007, Ext JS, LLC.
24955 * Originally Released Under LGPL - original licence link has changed is not relivant.
24958 * <script type="text/javascript">
24962 * @class Roo.bootstrap.PagingToolbar
24963 * @extends Roo.bootstrap.NavSimplebar
24964 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24966 * Create a new PagingToolbar
24967 * @param {Object} config The config object
24968 * @param {Roo.data.Store} store
24970 Roo.bootstrap.PagingToolbar = function(config)
24972 // old args format still supported... - xtype is prefered..
24973 // created from xtype...
24975 this.ds = config.dataSource;
24977 if (config.store && !this.ds) {
24978 this.store= Roo.factory(config.store, Roo.data);
24979 this.ds = this.store;
24980 this.ds.xmodule = this.xmodule || false;
24983 this.toolbarItems = [];
24984 if (config.items) {
24985 this.toolbarItems = config.items;
24988 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24993 this.bind(this.ds);
24996 if (Roo.bootstrap.version == 4) {
24997 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24999 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
25004 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
25006 * @cfg {Roo.data.Store} dataSource
25007 * The underlying data store providing the paged data
25010 * @cfg {String/HTMLElement/Element} container
25011 * container The id or element that will contain the toolbar
25014 * @cfg {Boolean} displayInfo
25015 * True to display the displayMsg (defaults to false)
25018 * @cfg {Number} pageSize
25019 * The number of records to display per page (defaults to 20)
25023 * @cfg {String} displayMsg
25024 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25026 displayMsg : 'Displaying {0} - {1} of {2}',
25028 * @cfg {String} emptyMsg
25029 * The message to display when no records are found (defaults to "No data to display")
25031 emptyMsg : 'No data to display',
25033 * Customizable piece of the default paging text (defaults to "Page")
25036 beforePageText : "Page",
25038 * Customizable piece of the default paging text (defaults to "of %0")
25041 afterPageText : "of {0}",
25043 * Customizable piece of the default paging text (defaults to "First Page")
25046 firstText : "First Page",
25048 * Customizable piece of the default paging text (defaults to "Previous Page")
25051 prevText : "Previous Page",
25053 * Customizable piece of the default paging text (defaults to "Next Page")
25056 nextText : "Next Page",
25058 * Customizable piece of the default paging text (defaults to "Last Page")
25061 lastText : "Last Page",
25063 * Customizable piece of the default paging text (defaults to "Refresh")
25066 refreshText : "Refresh",
25070 onRender : function(ct, position)
25072 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25073 this.navgroup.parentId = this.id;
25074 this.navgroup.onRender(this.el, null);
25075 // add the buttons to the navgroup
25077 if(this.displayInfo){
25078 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25079 this.displayEl = this.el.select('.x-paging-info', true).first();
25080 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25081 // this.displayEl = navel.el.select('span',true).first();
25087 Roo.each(_this.buttons, function(e){ // this might need to use render????
25088 Roo.factory(e).render(_this.el);
25092 Roo.each(_this.toolbarItems, function(e) {
25093 _this.navgroup.addItem(e);
25097 this.first = this.navgroup.addItem({
25098 tooltip: this.firstText,
25099 cls: "prev btn-outline-secondary",
25100 html : ' <i class="fa fa-step-backward"></i>',
25102 preventDefault: true,
25103 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25106 this.prev = this.navgroup.addItem({
25107 tooltip: this.prevText,
25108 cls: "prev btn-outline-secondary",
25109 html : ' <i class="fa fa-backward"></i>',
25111 preventDefault: true,
25112 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25114 //this.addSeparator();
25117 var field = this.navgroup.addItem( {
25119 cls : 'x-paging-position btn-outline-secondary',
25121 html : this.beforePageText +
25122 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25123 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25126 this.field = field.el.select('input', true).first();
25127 this.field.on("keydown", this.onPagingKeydown, this);
25128 this.field.on("focus", function(){this.dom.select();});
25131 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25132 //this.field.setHeight(18);
25133 //this.addSeparator();
25134 this.next = this.navgroup.addItem({
25135 tooltip: this.nextText,
25136 cls: "next btn-outline-secondary",
25137 html : ' <i class="fa fa-forward"></i>',
25139 preventDefault: true,
25140 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25142 this.last = this.navgroup.addItem({
25143 tooltip: this.lastText,
25144 html : ' <i class="fa fa-step-forward"></i>',
25145 cls: "next btn-outline-secondary",
25147 preventDefault: true,
25148 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25150 //this.addSeparator();
25151 this.loading = this.navgroup.addItem({
25152 tooltip: this.refreshText,
25153 cls: "btn-outline-secondary",
25154 html : ' <i class="fa fa-refresh"></i>',
25155 preventDefault: true,
25156 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25162 updateInfo : function(){
25163 if(this.displayEl){
25164 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25165 var msg = count == 0 ?
25169 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25171 this.displayEl.update(msg);
25176 onLoad : function(ds, r, o)
25178 this.cursor = o.params.start ? o.params.start : 0;
25180 var d = this.getPageData(),
25185 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25186 this.field.dom.value = ap;
25187 this.first.setDisabled(ap == 1);
25188 this.prev.setDisabled(ap == 1);
25189 this.next.setDisabled(ap == ps);
25190 this.last.setDisabled(ap == ps);
25191 this.loading.enable();
25196 getPageData : function(){
25197 var total = this.ds.getTotalCount();
25200 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25201 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25206 onLoadError : function(){
25207 this.loading.enable();
25211 onPagingKeydown : function(e){
25212 var k = e.getKey();
25213 var d = this.getPageData();
25215 var v = this.field.dom.value, pageNum;
25216 if(!v || isNaN(pageNum = parseInt(v, 10))){
25217 this.field.dom.value = d.activePage;
25220 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25221 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25224 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))
25226 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25227 this.field.dom.value = pageNum;
25228 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25231 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25233 var v = this.field.dom.value, pageNum;
25234 var increment = (e.shiftKey) ? 10 : 1;
25235 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25238 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25239 this.field.dom.value = d.activePage;
25242 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25244 this.field.dom.value = parseInt(v, 10) + increment;
25245 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25246 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25253 beforeLoad : function(){
25255 this.loading.disable();
25260 onClick : function(which){
25269 ds.load({params:{start: 0, limit: this.pageSize}});
25272 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25275 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25278 var total = ds.getTotalCount();
25279 var extra = total % this.pageSize;
25280 var lastStart = extra ? (total - extra) : total-this.pageSize;
25281 ds.load({params:{start: lastStart, limit: this.pageSize}});
25284 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25290 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25291 * @param {Roo.data.Store} store The data store to unbind
25293 unbind : function(ds){
25294 ds.un("beforeload", this.beforeLoad, this);
25295 ds.un("load", this.onLoad, this);
25296 ds.un("loadexception", this.onLoadError, this);
25297 ds.un("remove", this.updateInfo, this);
25298 ds.un("add", this.updateInfo, this);
25299 this.ds = undefined;
25303 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25304 * @param {Roo.data.Store} store The data store to bind
25306 bind : function(ds){
25307 ds.on("beforeload", this.beforeLoad, this);
25308 ds.on("load", this.onLoad, this);
25309 ds.on("loadexception", this.onLoadError, this);
25310 ds.on("remove", this.updateInfo, this);
25311 ds.on("add", this.updateInfo, this);
25322 * @class Roo.bootstrap.MessageBar
25323 * @extends Roo.bootstrap.Component
25324 * Bootstrap MessageBar class
25325 * @cfg {String} html contents of the MessageBar
25326 * @cfg {String} weight (info | success | warning | danger) default info
25327 * @cfg {String} beforeClass insert the bar before the given class
25328 * @cfg {Boolean} closable (true | false) default false
25329 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25332 * Create a new Element
25333 * @param {Object} config The config object
25336 Roo.bootstrap.MessageBar = function(config){
25337 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25340 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25346 beforeClass: 'bootstrap-sticky-wrap',
25348 getAutoCreate : function(){
25352 cls: 'alert alert-dismissable alert-' + this.weight,
25357 html: this.html || ''
25363 cfg.cls += ' alert-messages-fixed';
25377 onRender : function(ct, position)
25379 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25382 var cfg = Roo.apply({}, this.getAutoCreate());
25386 cfg.cls += ' ' + this.cls;
25389 cfg.style = this.style;
25391 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25393 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25396 this.el.select('>button.close').on('click', this.hide, this);
25402 if (!this.rendered) {
25408 this.fireEvent('show', this);
25414 if (!this.rendered) {
25420 this.fireEvent('hide', this);
25423 update : function()
25425 // var e = this.el.dom.firstChild;
25427 // if(this.closable){
25428 // e = e.nextSibling;
25431 // e.data = this.html || '';
25433 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25449 * @class Roo.bootstrap.Graph
25450 * @extends Roo.bootstrap.Component
25451 * Bootstrap Graph class
25455 @cfg {String} graphtype bar | vbar | pie
25456 @cfg {number} g_x coodinator | centre x (pie)
25457 @cfg {number} g_y coodinator | centre y (pie)
25458 @cfg {number} g_r radius (pie)
25459 @cfg {number} g_height height of the chart (respected by all elements in the set)
25460 @cfg {number} g_width width of the chart (respected by all elements in the set)
25461 @cfg {Object} title The title of the chart
25464 -opts (object) options for the chart
25466 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25467 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25469 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.
25470 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25472 o stretch (boolean)
25474 -opts (object) options for the pie
25477 o startAngle (number)
25478 o endAngle (number)
25482 * Create a new Input
25483 * @param {Object} config The config object
25486 Roo.bootstrap.Graph = function(config){
25487 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25493 * The img click event for the img.
25494 * @param {Roo.EventObject} e
25500 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25511 //g_colors: this.colors,
25518 getAutoCreate : function(){
25529 onRender : function(ct,position){
25532 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25534 if (typeof(Raphael) == 'undefined') {
25535 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25539 this.raphael = Raphael(this.el.dom);
25541 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25542 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25543 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25544 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25546 r.text(160, 10, "Single Series Chart").attr(txtattr);
25547 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25548 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25549 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25551 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25552 r.barchart(330, 10, 300, 220, data1);
25553 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25554 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25557 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25558 // r.barchart(30, 30, 560, 250, xdata, {
25559 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25560 // axis : "0 0 1 1",
25561 // axisxlabels : xdata
25562 // //yvalues : cols,
25565 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25567 // this.load(null,xdata,{
25568 // axis : "0 0 1 1",
25569 // axisxlabels : xdata
25574 load : function(graphtype,xdata,opts)
25576 this.raphael.clear();
25578 graphtype = this.graphtype;
25583 var r = this.raphael,
25584 fin = function () {
25585 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25587 fout = function () {
25588 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25590 pfin = function() {
25591 this.sector.stop();
25592 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25595 this.label[0].stop();
25596 this.label[0].attr({ r: 7.5 });
25597 this.label[1].attr({ "font-weight": 800 });
25600 pfout = function() {
25601 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25604 this.label[0].animate({ r: 5 }, 500, "bounce");
25605 this.label[1].attr({ "font-weight": 400 });
25611 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25614 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25617 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25618 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25620 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25627 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25632 setTitle: function(o)
25637 initEvents: function() {
25640 this.el.on('click', this.onClick, this);
25644 onClick : function(e)
25646 Roo.log('img onclick');
25647 this.fireEvent('click', this, e);
25659 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25662 * @class Roo.bootstrap.dash.NumberBox
25663 * @extends Roo.bootstrap.Component
25664 * Bootstrap NumberBox class
25665 * @cfg {String} headline Box headline
25666 * @cfg {String} content Box content
25667 * @cfg {String} icon Box icon
25668 * @cfg {String} footer Footer text
25669 * @cfg {String} fhref Footer href
25672 * Create a new NumberBox
25673 * @param {Object} config The config object
25677 Roo.bootstrap.dash.NumberBox = function(config){
25678 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25682 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25691 getAutoCreate : function(){
25695 cls : 'small-box ',
25703 cls : 'roo-headline',
25704 html : this.headline
25708 cls : 'roo-content',
25709 html : this.content
25723 cls : 'ion ' + this.icon
25732 cls : 'small-box-footer',
25733 href : this.fhref || '#',
25737 cfg.cn.push(footer);
25744 onRender : function(ct,position){
25745 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25752 setHeadline: function (value)
25754 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25757 setFooter: function (value, href)
25759 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25762 this.el.select('a.small-box-footer',true).first().attr('href', href);
25767 setContent: function (value)
25769 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25772 initEvents: function()
25786 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25789 * @class Roo.bootstrap.dash.TabBox
25790 * @extends Roo.bootstrap.Component
25791 * Bootstrap TabBox class
25792 * @cfg {String} title Title of the TabBox
25793 * @cfg {String} icon Icon of the TabBox
25794 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25795 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25798 * Create a new TabBox
25799 * @param {Object} config The config object
25803 Roo.bootstrap.dash.TabBox = function(config){
25804 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25809 * When a pane is added
25810 * @param {Roo.bootstrap.dash.TabPane} pane
25814 * @event activatepane
25815 * When a pane is activated
25816 * @param {Roo.bootstrap.dash.TabPane} pane
25818 "activatepane" : true
25826 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25831 tabScrollable : false,
25833 getChildContainer : function()
25835 return this.el.select('.tab-content', true).first();
25838 getAutoCreate : function(){
25842 cls: 'pull-left header',
25850 cls: 'fa ' + this.icon
25856 cls: 'nav nav-tabs pull-right',
25862 if(this.tabScrollable){
25869 cls: 'nav nav-tabs pull-right',
25880 cls: 'nav-tabs-custom',
25885 cls: 'tab-content no-padding',
25893 initEvents : function()
25895 //Roo.log('add add pane handler');
25896 this.on('addpane', this.onAddPane, this);
25899 * Updates the box title
25900 * @param {String} html to set the title to.
25902 setTitle : function(value)
25904 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25906 onAddPane : function(pane)
25908 this.panes.push(pane);
25909 //Roo.log('addpane');
25911 // tabs are rendere left to right..
25912 if(!this.showtabs){
25916 var ctr = this.el.select('.nav-tabs', true).first();
25919 var existing = ctr.select('.nav-tab',true);
25920 var qty = existing.getCount();;
25923 var tab = ctr.createChild({
25925 cls : 'nav-tab' + (qty ? '' : ' active'),
25933 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25936 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25938 pane.el.addClass('active');
25943 onTabClick : function(ev,un,ob,pane)
25945 //Roo.log('tab - prev default');
25946 ev.preventDefault();
25949 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25950 pane.tab.addClass('active');
25951 //Roo.log(pane.title);
25952 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25953 // technically we should have a deactivate event.. but maybe add later.
25954 // and it should not de-activate the selected tab...
25955 this.fireEvent('activatepane', pane);
25956 pane.el.addClass('active');
25957 pane.fireEvent('activate');
25962 getActivePane : function()
25965 Roo.each(this.panes, function(p) {
25966 if(p.el.hasClass('active')){
25987 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25989 * @class Roo.bootstrap.TabPane
25990 * @extends Roo.bootstrap.Component
25991 * Bootstrap TabPane class
25992 * @cfg {Boolean} active (false | true) Default false
25993 * @cfg {String} title title of panel
25997 * Create a new TabPane
25998 * @param {Object} config The config object
26001 Roo.bootstrap.dash.TabPane = function(config){
26002 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26008 * When a pane is activated
26009 * @param {Roo.bootstrap.dash.TabPane} pane
26016 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26021 // the tabBox that this is attached to.
26024 getAutoCreate : function()
26032 cfg.cls += ' active';
26037 initEvents : function()
26039 //Roo.log('trigger add pane handler');
26040 this.parent().fireEvent('addpane', this)
26044 * Updates the tab title
26045 * @param {String} html to set the title to.
26047 setTitle: function(str)
26053 this.tab.select('a', true).first().dom.innerHTML = str;
26070 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26073 * @class Roo.bootstrap.menu.Menu
26074 * @extends Roo.bootstrap.Component
26075 * Bootstrap Menu class - container for Menu
26076 * @cfg {String} html Text of the menu
26077 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26078 * @cfg {String} icon Font awesome icon
26079 * @cfg {String} pos Menu align to (top | bottom) default bottom
26083 * Create a new Menu
26084 * @param {Object} config The config object
26088 Roo.bootstrap.menu.Menu = function(config){
26089 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26093 * @event beforeshow
26094 * Fires before this menu is displayed
26095 * @param {Roo.bootstrap.menu.Menu} this
26099 * @event beforehide
26100 * Fires before this menu is hidden
26101 * @param {Roo.bootstrap.menu.Menu} this
26106 * Fires after this menu is displayed
26107 * @param {Roo.bootstrap.menu.Menu} this
26112 * Fires after this menu is hidden
26113 * @param {Roo.bootstrap.menu.Menu} this
26118 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26119 * @param {Roo.bootstrap.menu.Menu} this
26120 * @param {Roo.EventObject} e
26127 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26131 weight : 'default',
26136 getChildContainer : function() {
26137 if(this.isSubMenu){
26141 return this.el.select('ul.dropdown-menu', true).first();
26144 getAutoCreate : function()
26149 cls : 'roo-menu-text',
26157 cls : 'fa ' + this.icon
26168 cls : 'dropdown-button btn btn-' + this.weight,
26173 cls : 'dropdown-toggle btn btn-' + this.weight,
26183 cls : 'dropdown-menu'
26189 if(this.pos == 'top'){
26190 cfg.cls += ' dropup';
26193 if(this.isSubMenu){
26196 cls : 'dropdown-menu'
26203 onRender : function(ct, position)
26205 this.isSubMenu = ct.hasClass('dropdown-submenu');
26207 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26210 initEvents : function()
26212 if(this.isSubMenu){
26216 this.hidden = true;
26218 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26219 this.triggerEl.on('click', this.onTriggerPress, this);
26221 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26222 this.buttonEl.on('click', this.onClick, this);
26228 if(this.isSubMenu){
26232 return this.el.select('ul.dropdown-menu', true).first();
26235 onClick : function(e)
26237 this.fireEvent("click", this, e);
26240 onTriggerPress : function(e)
26242 if (this.isVisible()) {
26249 isVisible : function(){
26250 return !this.hidden;
26255 this.fireEvent("beforeshow", this);
26257 this.hidden = false;
26258 this.el.addClass('open');
26260 Roo.get(document).on("mouseup", this.onMouseUp, this);
26262 this.fireEvent("show", this);
26269 this.fireEvent("beforehide", this);
26271 this.hidden = true;
26272 this.el.removeClass('open');
26274 Roo.get(document).un("mouseup", this.onMouseUp);
26276 this.fireEvent("hide", this);
26279 onMouseUp : function()
26293 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26296 * @class Roo.bootstrap.menu.Item
26297 * @extends Roo.bootstrap.Component
26298 * Bootstrap MenuItem class
26299 * @cfg {Boolean} submenu (true | false) default false
26300 * @cfg {String} html text of the item
26301 * @cfg {String} href the link
26302 * @cfg {Boolean} disable (true | false) default false
26303 * @cfg {Boolean} preventDefault (true | false) default true
26304 * @cfg {String} icon Font awesome icon
26305 * @cfg {String} pos Submenu align to (left | right) default right
26309 * Create a new Item
26310 * @param {Object} config The config object
26314 Roo.bootstrap.menu.Item = function(config){
26315 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26319 * Fires when the mouse is hovering over this menu
26320 * @param {Roo.bootstrap.menu.Item} this
26321 * @param {Roo.EventObject} e
26326 * Fires when the mouse exits this menu
26327 * @param {Roo.bootstrap.menu.Item} this
26328 * @param {Roo.EventObject} e
26334 * The raw click event for the entire grid.
26335 * @param {Roo.EventObject} e
26341 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26346 preventDefault: true,
26351 getAutoCreate : function()
26356 cls : 'roo-menu-item-text',
26364 cls : 'fa ' + this.icon
26373 href : this.href || '#',
26380 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26384 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26386 if(this.pos == 'left'){
26387 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26394 initEvents : function()
26396 this.el.on('mouseover', this.onMouseOver, this);
26397 this.el.on('mouseout', this.onMouseOut, this);
26399 this.el.select('a', true).first().on('click', this.onClick, this);
26403 onClick : function(e)
26405 if(this.preventDefault){
26406 e.preventDefault();
26409 this.fireEvent("click", this, e);
26412 onMouseOver : function(e)
26414 if(this.submenu && this.pos == 'left'){
26415 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26418 this.fireEvent("mouseover", this, e);
26421 onMouseOut : function(e)
26423 this.fireEvent("mouseout", this, e);
26435 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26438 * @class Roo.bootstrap.menu.Separator
26439 * @extends Roo.bootstrap.Component
26440 * Bootstrap Separator class
26443 * Create a new Separator
26444 * @param {Object} config The config object
26448 Roo.bootstrap.menu.Separator = function(config){
26449 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26452 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26454 getAutoCreate : function(){
26475 * @class Roo.bootstrap.Tooltip
26476 * Bootstrap Tooltip class
26477 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26478 * to determine which dom element triggers the tooltip.
26480 * It needs to add support for additional attributes like tooltip-position
26483 * Create a new Toolti
26484 * @param {Object} config The config object
26487 Roo.bootstrap.Tooltip = function(config){
26488 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26490 this.alignment = Roo.bootstrap.Tooltip.alignment;
26492 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26493 this.alignment = config.alignment;
26498 Roo.apply(Roo.bootstrap.Tooltip, {
26500 * @function init initialize tooltip monitoring.
26504 currentTip : false,
26505 currentRegion : false,
26511 Roo.get(document).on('mouseover', this.enter ,this);
26512 Roo.get(document).on('mouseout', this.leave, this);
26515 this.currentTip = new Roo.bootstrap.Tooltip();
26518 enter : function(ev)
26520 var dom = ev.getTarget();
26522 //Roo.log(['enter',dom]);
26523 var el = Roo.fly(dom);
26524 if (this.currentEl) {
26526 //Roo.log(this.currentEl);
26527 //Roo.log(this.currentEl.contains(dom));
26528 if (this.currentEl == el) {
26531 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26537 if (this.currentTip.el) {
26538 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26542 if(!el || el.dom == document){
26548 // you can not look for children, as if el is the body.. then everythign is the child..
26549 if (!el.attr('tooltip')) { //
26550 if (!el.select("[tooltip]").elements.length) {
26553 // is the mouse over this child...?
26554 bindEl = el.select("[tooltip]").first();
26555 var xy = ev.getXY();
26556 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26557 //Roo.log("not in region.");
26560 //Roo.log("child element over..");
26563 this.currentEl = bindEl;
26564 this.currentTip.bind(bindEl);
26565 this.currentRegion = Roo.lib.Region.getRegion(dom);
26566 this.currentTip.enter();
26569 leave : function(ev)
26571 var dom = ev.getTarget();
26572 //Roo.log(['leave',dom]);
26573 if (!this.currentEl) {
26578 if (dom != this.currentEl.dom) {
26581 var xy = ev.getXY();
26582 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26585 // only activate leave if mouse cursor is outside... bounding box..
26590 if (this.currentTip) {
26591 this.currentTip.leave();
26593 //Roo.log('clear currentEl');
26594 this.currentEl = false;
26599 'left' : ['r-l', [-2,0], 'right'],
26600 'right' : ['l-r', [2,0], 'left'],
26601 'bottom' : ['t-b', [0,2], 'top'],
26602 'top' : [ 'b-t', [0,-2], 'bottom']
26608 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26613 delay : null, // can be { show : 300 , hide: 500}
26617 hoverState : null, //???
26619 placement : 'bottom',
26623 getAutoCreate : function(){
26630 cls : 'tooltip-arrow'
26633 cls : 'tooltip-inner'
26640 bind : function(el)
26646 enter : function () {
26648 if (this.timeout != null) {
26649 clearTimeout(this.timeout);
26652 this.hoverState = 'in';
26653 //Roo.log("enter - show");
26654 if (!this.delay || !this.delay.show) {
26659 this.timeout = setTimeout(function () {
26660 if (_t.hoverState == 'in') {
26663 }, this.delay.show);
26667 clearTimeout(this.timeout);
26669 this.hoverState = 'out';
26670 if (!this.delay || !this.delay.hide) {
26676 this.timeout = setTimeout(function () {
26677 //Roo.log("leave - timeout");
26679 if (_t.hoverState == 'out') {
26681 Roo.bootstrap.Tooltip.currentEl = false;
26686 show : function (msg)
26689 this.render(document.body);
26692 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26694 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26696 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26698 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26700 var placement = typeof this.placement == 'function' ?
26701 this.placement.call(this, this.el, on_el) :
26704 var autoToken = /\s?auto?\s?/i;
26705 var autoPlace = autoToken.test(placement);
26707 placement = placement.replace(autoToken, '') || 'top';
26711 //this.el.setXY([0,0]);
26713 //this.el.dom.style.display='block';
26715 //this.el.appendTo(on_el);
26717 var p = this.getPosition();
26718 var box = this.el.getBox();
26724 var align = this.alignment[placement];
26726 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26728 if(placement == 'top' || placement == 'bottom'){
26730 placement = 'right';
26733 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26734 placement = 'left';
26737 var scroll = Roo.select('body', true).first().getScroll();
26739 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26743 align = this.alignment[placement];
26746 this.el.alignTo(this.bindEl, align[0],align[1]);
26747 //var arrow = this.el.select('.arrow',true).first();
26748 //arrow.set(align[2],
26750 this.el.addClass(placement);
26752 this.el.addClass('in fade');
26754 this.hoverState = null;
26756 if (this.el.hasClass('fade')) {
26767 //this.el.setXY([0,0]);
26768 this.el.removeClass('in');
26784 * @class Roo.bootstrap.LocationPicker
26785 * @extends Roo.bootstrap.Component
26786 * Bootstrap LocationPicker class
26787 * @cfg {Number} latitude Position when init default 0
26788 * @cfg {Number} longitude Position when init default 0
26789 * @cfg {Number} zoom default 15
26790 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26791 * @cfg {Boolean} mapTypeControl default false
26792 * @cfg {Boolean} disableDoubleClickZoom default false
26793 * @cfg {Boolean} scrollwheel default true
26794 * @cfg {Boolean} streetViewControl default false
26795 * @cfg {Number} radius default 0
26796 * @cfg {String} locationName
26797 * @cfg {Boolean} draggable default true
26798 * @cfg {Boolean} enableAutocomplete default false
26799 * @cfg {Boolean} enableReverseGeocode default true
26800 * @cfg {String} markerTitle
26803 * Create a new LocationPicker
26804 * @param {Object} config The config object
26808 Roo.bootstrap.LocationPicker = function(config){
26810 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26815 * Fires when the picker initialized.
26816 * @param {Roo.bootstrap.LocationPicker} this
26817 * @param {Google Location} location
26821 * @event positionchanged
26822 * Fires when the picker position changed.
26823 * @param {Roo.bootstrap.LocationPicker} this
26824 * @param {Google Location} location
26826 positionchanged : true,
26829 * Fires when the map resize.
26830 * @param {Roo.bootstrap.LocationPicker} this
26835 * Fires when the map show.
26836 * @param {Roo.bootstrap.LocationPicker} this
26841 * Fires when the map hide.
26842 * @param {Roo.bootstrap.LocationPicker} this
26847 * Fires when click the map.
26848 * @param {Roo.bootstrap.LocationPicker} this
26849 * @param {Map event} e
26853 * @event mapRightClick
26854 * Fires when right click the map.
26855 * @param {Roo.bootstrap.LocationPicker} this
26856 * @param {Map event} e
26858 mapRightClick : true,
26860 * @event markerClick
26861 * Fires when click the marker.
26862 * @param {Roo.bootstrap.LocationPicker} this
26863 * @param {Map event} e
26865 markerClick : true,
26867 * @event markerRightClick
26868 * Fires when right click the marker.
26869 * @param {Roo.bootstrap.LocationPicker} this
26870 * @param {Map event} e
26872 markerRightClick : true,
26874 * @event OverlayViewDraw
26875 * Fires when OverlayView Draw
26876 * @param {Roo.bootstrap.LocationPicker} this
26878 OverlayViewDraw : true,
26880 * @event OverlayViewOnAdd
26881 * Fires when OverlayView Draw
26882 * @param {Roo.bootstrap.LocationPicker} this
26884 OverlayViewOnAdd : true,
26886 * @event OverlayViewOnRemove
26887 * Fires when OverlayView Draw
26888 * @param {Roo.bootstrap.LocationPicker} this
26890 OverlayViewOnRemove : true,
26892 * @event OverlayViewShow
26893 * Fires when OverlayView Draw
26894 * @param {Roo.bootstrap.LocationPicker} this
26895 * @param {Pixel} cpx
26897 OverlayViewShow : true,
26899 * @event OverlayViewHide
26900 * Fires when OverlayView Draw
26901 * @param {Roo.bootstrap.LocationPicker} this
26903 OverlayViewHide : true,
26905 * @event loadexception
26906 * Fires when load google lib failed.
26907 * @param {Roo.bootstrap.LocationPicker} this
26909 loadexception : true
26914 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26916 gMapContext: false,
26922 mapTypeControl: false,
26923 disableDoubleClickZoom: false,
26925 streetViewControl: false,
26929 enableAutocomplete: false,
26930 enableReverseGeocode: true,
26933 getAutoCreate: function()
26938 cls: 'roo-location-picker'
26944 initEvents: function(ct, position)
26946 if(!this.el.getWidth() || this.isApplied()){
26950 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26955 initial: function()
26957 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26958 this.fireEvent('loadexception', this);
26962 if(!this.mapTypeId){
26963 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26966 this.gMapContext = this.GMapContext();
26968 this.initOverlayView();
26970 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26974 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26975 _this.setPosition(_this.gMapContext.marker.position);
26978 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26979 _this.fireEvent('mapClick', this, event);
26983 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26984 _this.fireEvent('mapRightClick', this, event);
26988 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26989 _this.fireEvent('markerClick', this, event);
26993 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26994 _this.fireEvent('markerRightClick', this, event);
26998 this.setPosition(this.gMapContext.location);
27000 this.fireEvent('initial', this, this.gMapContext.location);
27003 initOverlayView: function()
27007 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27011 _this.fireEvent('OverlayViewDraw', _this);
27016 _this.fireEvent('OverlayViewOnAdd', _this);
27019 onRemove: function()
27021 _this.fireEvent('OverlayViewOnRemove', _this);
27024 show: function(cpx)
27026 _this.fireEvent('OverlayViewShow', _this, cpx);
27031 _this.fireEvent('OverlayViewHide', _this);
27037 fromLatLngToContainerPixel: function(event)
27039 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27042 isApplied: function()
27044 return this.getGmapContext() == false ? false : true;
27047 getGmapContext: function()
27049 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27052 GMapContext: function()
27054 var position = new google.maps.LatLng(this.latitude, this.longitude);
27056 var _map = new google.maps.Map(this.el.dom, {
27059 mapTypeId: this.mapTypeId,
27060 mapTypeControl: this.mapTypeControl,
27061 disableDoubleClickZoom: this.disableDoubleClickZoom,
27062 scrollwheel: this.scrollwheel,
27063 streetViewControl: this.streetViewControl,
27064 locationName: this.locationName,
27065 draggable: this.draggable,
27066 enableAutocomplete: this.enableAutocomplete,
27067 enableReverseGeocode: this.enableReverseGeocode
27070 var _marker = new google.maps.Marker({
27071 position: position,
27073 title: this.markerTitle,
27074 draggable: this.draggable
27081 location: position,
27082 radius: this.radius,
27083 locationName: this.locationName,
27084 addressComponents: {
27085 formatted_address: null,
27086 addressLine1: null,
27087 addressLine2: null,
27089 streetNumber: null,
27093 stateOrProvince: null
27096 domContainer: this.el.dom,
27097 geodecoder: new google.maps.Geocoder()
27101 drawCircle: function(center, radius, options)
27103 if (this.gMapContext.circle != null) {
27104 this.gMapContext.circle.setMap(null);
27108 options = Roo.apply({}, options, {
27109 strokeColor: "#0000FF",
27110 strokeOpacity: .35,
27112 fillColor: "#0000FF",
27116 options.map = this.gMapContext.map;
27117 options.radius = radius;
27118 options.center = center;
27119 this.gMapContext.circle = new google.maps.Circle(options);
27120 return this.gMapContext.circle;
27126 setPosition: function(location)
27128 this.gMapContext.location = location;
27129 this.gMapContext.marker.setPosition(location);
27130 this.gMapContext.map.panTo(location);
27131 this.drawCircle(location, this.gMapContext.radius, {});
27135 if (this.gMapContext.settings.enableReverseGeocode) {
27136 this.gMapContext.geodecoder.geocode({
27137 latLng: this.gMapContext.location
27138 }, function(results, status) {
27140 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27141 _this.gMapContext.locationName = results[0].formatted_address;
27142 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27144 _this.fireEvent('positionchanged', this, location);
27151 this.fireEvent('positionchanged', this, location);
27156 google.maps.event.trigger(this.gMapContext.map, "resize");
27158 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27160 this.fireEvent('resize', this);
27163 setPositionByLatLng: function(latitude, longitude)
27165 this.setPosition(new google.maps.LatLng(latitude, longitude));
27168 getCurrentPosition: function()
27171 latitude: this.gMapContext.location.lat(),
27172 longitude: this.gMapContext.location.lng()
27176 getAddressName: function()
27178 return this.gMapContext.locationName;
27181 getAddressComponents: function()
27183 return this.gMapContext.addressComponents;
27186 address_component_from_google_geocode: function(address_components)
27190 for (var i = 0; i < address_components.length; i++) {
27191 var component = address_components[i];
27192 if (component.types.indexOf("postal_code") >= 0) {
27193 result.postalCode = component.short_name;
27194 } else if (component.types.indexOf("street_number") >= 0) {
27195 result.streetNumber = component.short_name;
27196 } else if (component.types.indexOf("route") >= 0) {
27197 result.streetName = component.short_name;
27198 } else if (component.types.indexOf("neighborhood") >= 0) {
27199 result.city = component.short_name;
27200 } else if (component.types.indexOf("locality") >= 0) {
27201 result.city = component.short_name;
27202 } else if (component.types.indexOf("sublocality") >= 0) {
27203 result.district = component.short_name;
27204 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27205 result.stateOrProvince = component.short_name;
27206 } else if (component.types.indexOf("country") >= 0) {
27207 result.country = component.short_name;
27211 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27212 result.addressLine2 = "";
27216 setZoomLevel: function(zoom)
27218 this.gMapContext.map.setZoom(zoom);
27231 this.fireEvent('show', this);
27242 this.fireEvent('hide', this);
27247 Roo.apply(Roo.bootstrap.LocationPicker, {
27249 OverlayView : function(map, options)
27251 options = options || {};
27258 * @class Roo.bootstrap.Alert
27259 * @extends Roo.bootstrap.Component
27260 * Bootstrap Alert class - shows an alert area box
27262 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27263 Enter a valid email address
27266 * @cfg {String} title The title of alert
27267 * @cfg {String} html The content of alert
27268 * @cfg {String} weight ( success | info | warning | danger )
27269 * @cfg {String} faicon font-awesomeicon
27272 * Create a new alert
27273 * @param {Object} config The config object
27277 Roo.bootstrap.Alert = function(config){
27278 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27282 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27289 getAutoCreate : function()
27298 cls : 'roo-alert-icon'
27303 cls : 'roo-alert-title',
27308 cls : 'roo-alert-text',
27315 cfg.cn[0].cls += ' fa ' + this.faicon;
27319 cfg.cls += ' alert-' + this.weight;
27325 initEvents: function()
27327 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27330 setTitle : function(str)
27332 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27335 setText : function(str)
27337 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27340 setWeight : function(weight)
27343 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27346 this.weight = weight;
27348 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27351 setIcon : function(icon)
27354 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27357 this.faicon = icon;
27359 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27380 * @class Roo.bootstrap.UploadCropbox
27381 * @extends Roo.bootstrap.Component
27382 * Bootstrap UploadCropbox class
27383 * @cfg {String} emptyText show when image has been loaded
27384 * @cfg {String} rotateNotify show when image too small to rotate
27385 * @cfg {Number} errorTimeout default 3000
27386 * @cfg {Number} minWidth default 300
27387 * @cfg {Number} minHeight default 300
27388 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27389 * @cfg {Boolean} isDocument (true|false) default false
27390 * @cfg {String} url action url
27391 * @cfg {String} paramName default 'imageUpload'
27392 * @cfg {String} method default POST
27393 * @cfg {Boolean} loadMask (true|false) default true
27394 * @cfg {Boolean} loadingText default 'Loading...'
27397 * Create a new UploadCropbox
27398 * @param {Object} config The config object
27401 Roo.bootstrap.UploadCropbox = function(config){
27402 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27406 * @event beforeselectfile
27407 * Fire before select file
27408 * @param {Roo.bootstrap.UploadCropbox} this
27410 "beforeselectfile" : true,
27413 * Fire after initEvent
27414 * @param {Roo.bootstrap.UploadCropbox} this
27419 * Fire after initEvent
27420 * @param {Roo.bootstrap.UploadCropbox} this
27421 * @param {String} data
27426 * Fire when preparing the file data
27427 * @param {Roo.bootstrap.UploadCropbox} this
27428 * @param {Object} file
27433 * Fire when get exception
27434 * @param {Roo.bootstrap.UploadCropbox} this
27435 * @param {XMLHttpRequest} xhr
27437 "exception" : true,
27439 * @event beforeloadcanvas
27440 * Fire before load the canvas
27441 * @param {Roo.bootstrap.UploadCropbox} this
27442 * @param {String} src
27444 "beforeloadcanvas" : true,
27447 * Fire when trash image
27448 * @param {Roo.bootstrap.UploadCropbox} this
27453 * Fire when download the image
27454 * @param {Roo.bootstrap.UploadCropbox} this
27458 * @event footerbuttonclick
27459 * Fire when footerbuttonclick
27460 * @param {Roo.bootstrap.UploadCropbox} this
27461 * @param {String} type
27463 "footerbuttonclick" : true,
27467 * @param {Roo.bootstrap.UploadCropbox} this
27472 * Fire when rotate the image
27473 * @param {Roo.bootstrap.UploadCropbox} this
27474 * @param {String} pos
27479 * Fire when inspect the file
27480 * @param {Roo.bootstrap.UploadCropbox} this
27481 * @param {Object} file
27486 * Fire when xhr upload the file
27487 * @param {Roo.bootstrap.UploadCropbox} this
27488 * @param {Object} data
27493 * Fire when arrange the file data
27494 * @param {Roo.bootstrap.UploadCropbox} this
27495 * @param {Object} formData
27500 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27503 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27505 emptyText : 'Click to upload image',
27506 rotateNotify : 'Image is too small to rotate',
27507 errorTimeout : 3000,
27521 cropType : 'image/jpeg',
27523 canvasLoaded : false,
27524 isDocument : false,
27526 paramName : 'imageUpload',
27528 loadingText : 'Loading...',
27531 getAutoCreate : function()
27535 cls : 'roo-upload-cropbox',
27539 cls : 'roo-upload-cropbox-selector',
27544 cls : 'roo-upload-cropbox-body',
27545 style : 'cursor:pointer',
27549 cls : 'roo-upload-cropbox-preview'
27553 cls : 'roo-upload-cropbox-thumb'
27557 cls : 'roo-upload-cropbox-empty-notify',
27558 html : this.emptyText
27562 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27563 html : this.rotateNotify
27569 cls : 'roo-upload-cropbox-footer',
27572 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27582 onRender : function(ct, position)
27584 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27586 if (this.buttons.length) {
27588 Roo.each(this.buttons, function(bb) {
27590 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27592 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27598 this.maskEl = this.el;
27602 initEvents : function()
27604 this.urlAPI = (window.createObjectURL && window) ||
27605 (window.URL && URL.revokeObjectURL && URL) ||
27606 (window.webkitURL && webkitURL);
27608 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27609 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27611 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27612 this.selectorEl.hide();
27614 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27615 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27617 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27618 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27619 this.thumbEl.hide();
27621 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27622 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27624 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27625 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27626 this.errorEl.hide();
27628 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27629 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27630 this.footerEl.hide();
27632 this.setThumbBoxSize();
27638 this.fireEvent('initial', this);
27645 window.addEventListener("resize", function() { _this.resize(); } );
27647 this.bodyEl.on('click', this.beforeSelectFile, this);
27650 this.bodyEl.on('touchstart', this.onTouchStart, this);
27651 this.bodyEl.on('touchmove', this.onTouchMove, this);
27652 this.bodyEl.on('touchend', this.onTouchEnd, this);
27656 this.bodyEl.on('mousedown', this.onMouseDown, this);
27657 this.bodyEl.on('mousemove', this.onMouseMove, this);
27658 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27659 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27660 Roo.get(document).on('mouseup', this.onMouseUp, this);
27663 this.selectorEl.on('change', this.onFileSelected, this);
27669 this.baseScale = 1;
27671 this.baseRotate = 1;
27672 this.dragable = false;
27673 this.pinching = false;
27676 this.cropData = false;
27677 this.notifyEl.dom.innerHTML = this.emptyText;
27679 this.selectorEl.dom.value = '';
27683 resize : function()
27685 if(this.fireEvent('resize', this) != false){
27686 this.setThumbBoxPosition();
27687 this.setCanvasPosition();
27691 onFooterButtonClick : function(e, el, o, type)
27694 case 'rotate-left' :
27695 this.onRotateLeft(e);
27697 case 'rotate-right' :
27698 this.onRotateRight(e);
27701 this.beforeSelectFile(e);
27716 this.fireEvent('footerbuttonclick', this, type);
27719 beforeSelectFile : function(e)
27721 e.preventDefault();
27723 if(this.fireEvent('beforeselectfile', this) != false){
27724 this.selectorEl.dom.click();
27728 onFileSelected : function(e)
27730 e.preventDefault();
27732 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27736 var file = this.selectorEl.dom.files[0];
27738 if(this.fireEvent('inspect', this, file) != false){
27739 this.prepare(file);
27744 trash : function(e)
27746 this.fireEvent('trash', this);
27749 download : function(e)
27751 this.fireEvent('download', this);
27754 loadCanvas : function(src)
27756 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27760 this.imageEl = document.createElement('img');
27764 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27766 this.imageEl.src = src;
27770 onLoadCanvas : function()
27772 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27773 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27775 this.bodyEl.un('click', this.beforeSelectFile, this);
27777 this.notifyEl.hide();
27778 this.thumbEl.show();
27779 this.footerEl.show();
27781 this.baseRotateLevel();
27783 if(this.isDocument){
27784 this.setThumbBoxSize();
27787 this.setThumbBoxPosition();
27789 this.baseScaleLevel();
27795 this.canvasLoaded = true;
27798 this.maskEl.unmask();
27803 setCanvasPosition : function()
27805 if(!this.canvasEl){
27809 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27810 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27812 this.previewEl.setLeft(pw);
27813 this.previewEl.setTop(ph);
27817 onMouseDown : function(e)
27821 this.dragable = true;
27822 this.pinching = false;
27824 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27825 this.dragable = false;
27829 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27830 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27834 onMouseMove : function(e)
27838 if(!this.canvasLoaded){
27842 if (!this.dragable){
27846 var minX = Math.ceil(this.thumbEl.getLeft(true));
27847 var minY = Math.ceil(this.thumbEl.getTop(true));
27849 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27850 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27852 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27853 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27855 x = x - this.mouseX;
27856 y = y - this.mouseY;
27858 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27859 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27861 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27862 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27864 this.previewEl.setLeft(bgX);
27865 this.previewEl.setTop(bgY);
27867 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27868 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27871 onMouseUp : function(e)
27875 this.dragable = false;
27878 onMouseWheel : function(e)
27882 this.startScale = this.scale;
27884 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27886 if(!this.zoomable()){
27887 this.scale = this.startScale;
27896 zoomable : function()
27898 var minScale = this.thumbEl.getWidth() / this.minWidth;
27900 if(this.minWidth < this.minHeight){
27901 minScale = this.thumbEl.getHeight() / this.minHeight;
27904 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27905 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27909 (this.rotate == 0 || this.rotate == 180) &&
27911 width > this.imageEl.OriginWidth ||
27912 height > this.imageEl.OriginHeight ||
27913 (width < this.minWidth && height < this.minHeight)
27921 (this.rotate == 90 || this.rotate == 270) &&
27923 width > this.imageEl.OriginWidth ||
27924 height > this.imageEl.OriginHeight ||
27925 (width < this.minHeight && height < this.minWidth)
27932 !this.isDocument &&
27933 (this.rotate == 0 || this.rotate == 180) &&
27935 width < this.minWidth ||
27936 width > this.imageEl.OriginWidth ||
27937 height < this.minHeight ||
27938 height > this.imageEl.OriginHeight
27945 !this.isDocument &&
27946 (this.rotate == 90 || this.rotate == 270) &&
27948 width < this.minHeight ||
27949 width > this.imageEl.OriginWidth ||
27950 height < this.minWidth ||
27951 height > this.imageEl.OriginHeight
27961 onRotateLeft : function(e)
27963 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27965 var minScale = this.thumbEl.getWidth() / this.minWidth;
27967 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27968 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27970 this.startScale = this.scale;
27972 while (this.getScaleLevel() < minScale){
27974 this.scale = this.scale + 1;
27976 if(!this.zoomable()){
27981 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27982 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27987 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27994 this.scale = this.startScale;
27996 this.onRotateFail();
28001 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28003 if(this.isDocument){
28004 this.setThumbBoxSize();
28005 this.setThumbBoxPosition();
28006 this.setCanvasPosition();
28011 this.fireEvent('rotate', this, 'left');
28015 onRotateRight : function(e)
28017 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28019 var minScale = this.thumbEl.getWidth() / this.minWidth;
28021 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28022 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28024 this.startScale = this.scale;
28026 while (this.getScaleLevel() < minScale){
28028 this.scale = this.scale + 1;
28030 if(!this.zoomable()){
28035 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28036 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28041 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28048 this.scale = this.startScale;
28050 this.onRotateFail();
28055 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28057 if(this.isDocument){
28058 this.setThumbBoxSize();
28059 this.setThumbBoxPosition();
28060 this.setCanvasPosition();
28065 this.fireEvent('rotate', this, 'right');
28068 onRotateFail : function()
28070 this.errorEl.show(true);
28074 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28079 this.previewEl.dom.innerHTML = '';
28081 var canvasEl = document.createElement("canvas");
28083 var contextEl = canvasEl.getContext("2d");
28085 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28086 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28087 var center = this.imageEl.OriginWidth / 2;
28089 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28090 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28091 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28092 center = this.imageEl.OriginHeight / 2;
28095 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28097 contextEl.translate(center, center);
28098 contextEl.rotate(this.rotate * Math.PI / 180);
28100 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28102 this.canvasEl = document.createElement("canvas");
28104 this.contextEl = this.canvasEl.getContext("2d");
28106 switch (this.rotate) {
28109 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28110 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28112 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28117 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28118 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28120 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28121 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);
28125 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28130 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28131 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28133 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28134 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);
28138 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);
28143 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28144 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28146 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28147 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28151 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);
28158 this.previewEl.appendChild(this.canvasEl);
28160 this.setCanvasPosition();
28165 if(!this.canvasLoaded){
28169 var imageCanvas = document.createElement("canvas");
28171 var imageContext = imageCanvas.getContext("2d");
28173 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28174 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28176 var center = imageCanvas.width / 2;
28178 imageContext.translate(center, center);
28180 imageContext.rotate(this.rotate * Math.PI / 180);
28182 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28184 var canvas = document.createElement("canvas");
28186 var context = canvas.getContext("2d");
28188 canvas.width = this.minWidth;
28189 canvas.height = this.minHeight;
28191 switch (this.rotate) {
28194 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28195 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28197 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28198 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28200 var targetWidth = this.minWidth - 2 * x;
28201 var targetHeight = this.minHeight - 2 * y;
28205 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28206 scale = targetWidth / width;
28209 if(x > 0 && y == 0){
28210 scale = targetHeight / height;
28213 if(x > 0 && y > 0){
28214 scale = targetWidth / width;
28216 if(width < height){
28217 scale = targetHeight / height;
28221 context.scale(scale, scale);
28223 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28224 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28226 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28227 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28229 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28234 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28235 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28237 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28238 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28240 var targetWidth = this.minWidth - 2 * x;
28241 var targetHeight = this.minHeight - 2 * y;
28245 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28246 scale = targetWidth / width;
28249 if(x > 0 && y == 0){
28250 scale = targetHeight / height;
28253 if(x > 0 && y > 0){
28254 scale = targetWidth / width;
28256 if(width < height){
28257 scale = targetHeight / height;
28261 context.scale(scale, scale);
28263 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28264 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28266 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28267 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28269 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28271 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28276 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28277 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28279 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28280 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28282 var targetWidth = this.minWidth - 2 * x;
28283 var targetHeight = this.minHeight - 2 * y;
28287 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28288 scale = targetWidth / width;
28291 if(x > 0 && y == 0){
28292 scale = targetHeight / height;
28295 if(x > 0 && y > 0){
28296 scale = targetWidth / width;
28298 if(width < height){
28299 scale = targetHeight / height;
28303 context.scale(scale, scale);
28305 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28306 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28308 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28309 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28311 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28312 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28314 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28319 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28320 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28322 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28323 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28325 var targetWidth = this.minWidth - 2 * x;
28326 var targetHeight = this.minHeight - 2 * y;
28330 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28331 scale = targetWidth / width;
28334 if(x > 0 && y == 0){
28335 scale = targetHeight / height;
28338 if(x > 0 && y > 0){
28339 scale = targetWidth / width;
28341 if(width < height){
28342 scale = targetHeight / height;
28346 context.scale(scale, scale);
28348 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28349 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28351 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28352 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28354 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28356 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28363 this.cropData = canvas.toDataURL(this.cropType);
28365 if(this.fireEvent('crop', this, this.cropData) !== false){
28366 this.process(this.file, this.cropData);
28373 setThumbBoxSize : function()
28377 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28378 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28379 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28381 this.minWidth = width;
28382 this.minHeight = height;
28384 if(this.rotate == 90 || this.rotate == 270){
28385 this.minWidth = height;
28386 this.minHeight = width;
28391 width = Math.ceil(this.minWidth * height / this.minHeight);
28393 if(this.minWidth > this.minHeight){
28395 height = Math.ceil(this.minHeight * width / this.minWidth);
28398 this.thumbEl.setStyle({
28399 width : width + 'px',
28400 height : height + 'px'
28407 setThumbBoxPosition : function()
28409 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28410 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28412 this.thumbEl.setLeft(x);
28413 this.thumbEl.setTop(y);
28417 baseRotateLevel : function()
28419 this.baseRotate = 1;
28422 typeof(this.exif) != 'undefined' &&
28423 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28424 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28426 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28429 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28433 baseScaleLevel : function()
28437 if(this.isDocument){
28439 if(this.baseRotate == 6 || this.baseRotate == 8){
28441 height = this.thumbEl.getHeight();
28442 this.baseScale = height / this.imageEl.OriginWidth;
28444 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28445 width = this.thumbEl.getWidth();
28446 this.baseScale = width / this.imageEl.OriginHeight;
28452 height = this.thumbEl.getHeight();
28453 this.baseScale = height / this.imageEl.OriginHeight;
28455 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28456 width = this.thumbEl.getWidth();
28457 this.baseScale = width / this.imageEl.OriginWidth;
28463 if(this.baseRotate == 6 || this.baseRotate == 8){
28465 width = this.thumbEl.getHeight();
28466 this.baseScale = width / this.imageEl.OriginHeight;
28468 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28469 height = this.thumbEl.getWidth();
28470 this.baseScale = height / this.imageEl.OriginHeight;
28473 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28474 height = this.thumbEl.getWidth();
28475 this.baseScale = height / this.imageEl.OriginHeight;
28477 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28478 width = this.thumbEl.getHeight();
28479 this.baseScale = width / this.imageEl.OriginWidth;
28486 width = this.thumbEl.getWidth();
28487 this.baseScale = width / this.imageEl.OriginWidth;
28489 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28490 height = this.thumbEl.getHeight();
28491 this.baseScale = height / this.imageEl.OriginHeight;
28494 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28496 height = this.thumbEl.getHeight();
28497 this.baseScale = height / this.imageEl.OriginHeight;
28499 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28500 width = this.thumbEl.getWidth();
28501 this.baseScale = width / this.imageEl.OriginWidth;
28509 getScaleLevel : function()
28511 return this.baseScale * Math.pow(1.1, this.scale);
28514 onTouchStart : function(e)
28516 if(!this.canvasLoaded){
28517 this.beforeSelectFile(e);
28521 var touches = e.browserEvent.touches;
28527 if(touches.length == 1){
28528 this.onMouseDown(e);
28532 if(touches.length != 2){
28538 for(var i = 0, finger; finger = touches[i]; i++){
28539 coords.push(finger.pageX, finger.pageY);
28542 var x = Math.pow(coords[0] - coords[2], 2);
28543 var y = Math.pow(coords[1] - coords[3], 2);
28545 this.startDistance = Math.sqrt(x + y);
28547 this.startScale = this.scale;
28549 this.pinching = true;
28550 this.dragable = false;
28554 onTouchMove : function(e)
28556 if(!this.pinching && !this.dragable){
28560 var touches = e.browserEvent.touches;
28567 this.onMouseMove(e);
28573 for(var i = 0, finger; finger = touches[i]; i++){
28574 coords.push(finger.pageX, finger.pageY);
28577 var x = Math.pow(coords[0] - coords[2], 2);
28578 var y = Math.pow(coords[1] - coords[3], 2);
28580 this.endDistance = Math.sqrt(x + y);
28582 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28584 if(!this.zoomable()){
28585 this.scale = this.startScale;
28593 onTouchEnd : function(e)
28595 this.pinching = false;
28596 this.dragable = false;
28600 process : function(file, crop)
28603 this.maskEl.mask(this.loadingText);
28606 this.xhr = new XMLHttpRequest();
28608 file.xhr = this.xhr;
28610 this.xhr.open(this.method, this.url, true);
28613 "Accept": "application/json",
28614 "Cache-Control": "no-cache",
28615 "X-Requested-With": "XMLHttpRequest"
28618 for (var headerName in headers) {
28619 var headerValue = headers[headerName];
28621 this.xhr.setRequestHeader(headerName, headerValue);
28627 this.xhr.onload = function()
28629 _this.xhrOnLoad(_this.xhr);
28632 this.xhr.onerror = function()
28634 _this.xhrOnError(_this.xhr);
28637 var formData = new FormData();
28639 formData.append('returnHTML', 'NO');
28642 formData.append('crop', crop);
28645 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28646 formData.append(this.paramName, file, file.name);
28649 if(typeof(file.filename) != 'undefined'){
28650 formData.append('filename', file.filename);
28653 if(typeof(file.mimetype) != 'undefined'){
28654 formData.append('mimetype', file.mimetype);
28657 if(this.fireEvent('arrange', this, formData) != false){
28658 this.xhr.send(formData);
28662 xhrOnLoad : function(xhr)
28665 this.maskEl.unmask();
28668 if (xhr.readyState !== 4) {
28669 this.fireEvent('exception', this, xhr);
28673 var response = Roo.decode(xhr.responseText);
28675 if(!response.success){
28676 this.fireEvent('exception', this, xhr);
28680 var response = Roo.decode(xhr.responseText);
28682 this.fireEvent('upload', this, response);
28686 xhrOnError : function()
28689 this.maskEl.unmask();
28692 Roo.log('xhr on error');
28694 var response = Roo.decode(xhr.responseText);
28700 prepare : function(file)
28703 this.maskEl.mask(this.loadingText);
28709 if(typeof(file) === 'string'){
28710 this.loadCanvas(file);
28714 if(!file || !this.urlAPI){
28719 this.cropType = file.type;
28723 if(this.fireEvent('prepare', this, this.file) != false){
28725 var reader = new FileReader();
28727 reader.onload = function (e) {
28728 if (e.target.error) {
28729 Roo.log(e.target.error);
28733 var buffer = e.target.result,
28734 dataView = new DataView(buffer),
28736 maxOffset = dataView.byteLength - 4,
28740 if (dataView.getUint16(0) === 0xffd8) {
28741 while (offset < maxOffset) {
28742 markerBytes = dataView.getUint16(offset);
28744 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28745 markerLength = dataView.getUint16(offset + 2) + 2;
28746 if (offset + markerLength > dataView.byteLength) {
28747 Roo.log('Invalid meta data: Invalid segment size.');
28751 if(markerBytes == 0xffe1){
28752 _this.parseExifData(
28759 offset += markerLength;
28769 var url = _this.urlAPI.createObjectURL(_this.file);
28771 _this.loadCanvas(url);
28776 reader.readAsArrayBuffer(this.file);
28782 parseExifData : function(dataView, offset, length)
28784 var tiffOffset = offset + 10,
28788 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28789 // No Exif data, might be XMP data instead
28793 // Check for the ASCII code for "Exif" (0x45786966):
28794 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28795 // No Exif data, might be XMP data instead
28798 if (tiffOffset + 8 > dataView.byteLength) {
28799 Roo.log('Invalid Exif data: Invalid segment size.');
28802 // Check for the two null bytes:
28803 if (dataView.getUint16(offset + 8) !== 0x0000) {
28804 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28807 // Check the byte alignment:
28808 switch (dataView.getUint16(tiffOffset)) {
28810 littleEndian = true;
28813 littleEndian = false;
28816 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28819 // Check for the TIFF tag marker (0x002A):
28820 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28821 Roo.log('Invalid Exif data: Missing TIFF marker.');
28824 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28825 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28827 this.parseExifTags(
28830 tiffOffset + dirOffset,
28835 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28840 if (dirOffset + 6 > dataView.byteLength) {
28841 Roo.log('Invalid Exif data: Invalid directory offset.');
28844 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28845 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28846 if (dirEndOffset + 4 > dataView.byteLength) {
28847 Roo.log('Invalid Exif data: Invalid directory size.');
28850 for (i = 0; i < tagsNumber; i += 1) {
28854 dirOffset + 2 + 12 * i, // tag offset
28858 // Return the offset to the next directory:
28859 return dataView.getUint32(dirEndOffset, littleEndian);
28862 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28864 var tag = dataView.getUint16(offset, littleEndian);
28866 this.exif[tag] = this.getExifValue(
28870 dataView.getUint16(offset + 2, littleEndian), // tag type
28871 dataView.getUint32(offset + 4, littleEndian), // tag length
28876 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28878 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28887 Roo.log('Invalid Exif data: Invalid tag type.');
28891 tagSize = tagType.size * length;
28892 // Determine if the value is contained in the dataOffset bytes,
28893 // or if the value at the dataOffset is a pointer to the actual data:
28894 dataOffset = tagSize > 4 ?
28895 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28896 if (dataOffset + tagSize > dataView.byteLength) {
28897 Roo.log('Invalid Exif data: Invalid data offset.');
28900 if (length === 1) {
28901 return tagType.getValue(dataView, dataOffset, littleEndian);
28904 for (i = 0; i < length; i += 1) {
28905 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28908 if (tagType.ascii) {
28910 // Concatenate the chars:
28911 for (i = 0; i < values.length; i += 1) {
28913 // Ignore the terminating NULL byte(s):
28914 if (c === '\u0000') {
28926 Roo.apply(Roo.bootstrap.UploadCropbox, {
28928 'Orientation': 0x0112
28932 1: 0, //'top-left',
28934 3: 180, //'bottom-right',
28935 // 4: 'bottom-left',
28937 6: 90, //'right-top',
28938 // 7: 'right-bottom',
28939 8: 270 //'left-bottom'
28943 // byte, 8-bit unsigned int:
28945 getValue: function (dataView, dataOffset) {
28946 return dataView.getUint8(dataOffset);
28950 // ascii, 8-bit byte:
28952 getValue: function (dataView, dataOffset) {
28953 return String.fromCharCode(dataView.getUint8(dataOffset));
28958 // short, 16 bit int:
28960 getValue: function (dataView, dataOffset, littleEndian) {
28961 return dataView.getUint16(dataOffset, littleEndian);
28965 // long, 32 bit int:
28967 getValue: function (dataView, dataOffset, littleEndian) {
28968 return dataView.getUint32(dataOffset, littleEndian);
28972 // rational = two long values, first is numerator, second is denominator:
28974 getValue: function (dataView, dataOffset, littleEndian) {
28975 return dataView.getUint32(dataOffset, littleEndian) /
28976 dataView.getUint32(dataOffset + 4, littleEndian);
28980 // slong, 32 bit signed int:
28982 getValue: function (dataView, dataOffset, littleEndian) {
28983 return dataView.getInt32(dataOffset, littleEndian);
28987 // srational, two slongs, first is numerator, second is denominator:
28989 getValue: function (dataView, dataOffset, littleEndian) {
28990 return dataView.getInt32(dataOffset, littleEndian) /
28991 dataView.getInt32(dataOffset + 4, littleEndian);
29001 cls : 'btn-group roo-upload-cropbox-rotate-left',
29002 action : 'rotate-left',
29006 cls : 'btn btn-default',
29007 html : '<i class="fa fa-undo"></i>'
29013 cls : 'btn-group roo-upload-cropbox-picture',
29014 action : 'picture',
29018 cls : 'btn btn-default',
29019 html : '<i class="fa fa-picture-o"></i>'
29025 cls : 'btn-group roo-upload-cropbox-rotate-right',
29026 action : 'rotate-right',
29030 cls : 'btn btn-default',
29031 html : '<i class="fa fa-repeat"></i>'
29039 cls : 'btn-group roo-upload-cropbox-rotate-left',
29040 action : 'rotate-left',
29044 cls : 'btn btn-default',
29045 html : '<i class="fa fa-undo"></i>'
29051 cls : 'btn-group roo-upload-cropbox-download',
29052 action : 'download',
29056 cls : 'btn btn-default',
29057 html : '<i class="fa fa-download"></i>'
29063 cls : 'btn-group roo-upload-cropbox-crop',
29068 cls : 'btn btn-default',
29069 html : '<i class="fa fa-crop"></i>'
29075 cls : 'btn-group roo-upload-cropbox-trash',
29080 cls : 'btn btn-default',
29081 html : '<i class="fa fa-trash"></i>'
29087 cls : 'btn-group roo-upload-cropbox-rotate-right',
29088 action : 'rotate-right',
29092 cls : 'btn btn-default',
29093 html : '<i class="fa fa-repeat"></i>'
29101 cls : 'btn-group roo-upload-cropbox-rotate-left',
29102 action : 'rotate-left',
29106 cls : 'btn btn-default',
29107 html : '<i class="fa fa-undo"></i>'
29113 cls : 'btn-group roo-upload-cropbox-rotate-right',
29114 action : 'rotate-right',
29118 cls : 'btn btn-default',
29119 html : '<i class="fa fa-repeat"></i>'
29132 * @class Roo.bootstrap.DocumentManager
29133 * @extends Roo.bootstrap.Component
29134 * Bootstrap DocumentManager class
29135 * @cfg {String} paramName default 'imageUpload'
29136 * @cfg {String} toolTipName default 'filename'
29137 * @cfg {String} method default POST
29138 * @cfg {String} url action url
29139 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29140 * @cfg {Boolean} multiple multiple upload default true
29141 * @cfg {Number} thumbSize default 300
29142 * @cfg {String} fieldLabel
29143 * @cfg {Number} labelWidth default 4
29144 * @cfg {String} labelAlign (left|top) default left
29145 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29146 * @cfg {Number} labellg set the width of label (1-12)
29147 * @cfg {Number} labelmd set the width of label (1-12)
29148 * @cfg {Number} labelsm set the width of label (1-12)
29149 * @cfg {Number} labelxs set the width of label (1-12)
29152 * Create a new DocumentManager
29153 * @param {Object} config The config object
29156 Roo.bootstrap.DocumentManager = function(config){
29157 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29160 this.delegates = [];
29165 * Fire when initial the DocumentManager
29166 * @param {Roo.bootstrap.DocumentManager} this
29171 * inspect selected file
29172 * @param {Roo.bootstrap.DocumentManager} this
29173 * @param {File} file
29178 * Fire when xhr load exception
29179 * @param {Roo.bootstrap.DocumentManager} this
29180 * @param {XMLHttpRequest} xhr
29182 "exception" : true,
29184 * @event afterupload
29185 * Fire when xhr load exception
29186 * @param {Roo.bootstrap.DocumentManager} this
29187 * @param {XMLHttpRequest} xhr
29189 "afterupload" : true,
29192 * prepare the form data
29193 * @param {Roo.bootstrap.DocumentManager} this
29194 * @param {Object} formData
29199 * Fire when remove the file
29200 * @param {Roo.bootstrap.DocumentManager} this
29201 * @param {Object} file
29206 * Fire after refresh the file
29207 * @param {Roo.bootstrap.DocumentManager} this
29212 * Fire after click the image
29213 * @param {Roo.bootstrap.DocumentManager} this
29214 * @param {Object} file
29219 * Fire when upload a image and editable set to true
29220 * @param {Roo.bootstrap.DocumentManager} this
29221 * @param {Object} file
29225 * @event beforeselectfile
29226 * Fire before select file
29227 * @param {Roo.bootstrap.DocumentManager} this
29229 "beforeselectfile" : true,
29232 * Fire before process file
29233 * @param {Roo.bootstrap.DocumentManager} this
29234 * @param {Object} file
29238 * @event previewrendered
29239 * Fire when preview rendered
29240 * @param {Roo.bootstrap.DocumentManager} this
29241 * @param {Object} file
29243 "previewrendered" : true,
29246 "previewResize" : true
29251 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29260 paramName : 'imageUpload',
29261 toolTipName : 'filename',
29264 labelAlign : 'left',
29274 getAutoCreate : function()
29276 var managerWidget = {
29278 cls : 'roo-document-manager',
29282 cls : 'roo-document-manager-selector',
29287 cls : 'roo-document-manager-uploader',
29291 cls : 'roo-document-manager-upload-btn',
29292 html : '<i class="fa fa-plus"></i>'
29303 cls : 'column col-md-12',
29308 if(this.fieldLabel.length){
29313 cls : 'column col-md-12',
29314 html : this.fieldLabel
29318 cls : 'column col-md-12',
29323 if(this.labelAlign == 'left'){
29328 html : this.fieldLabel
29337 if(this.labelWidth > 12){
29338 content[0].style = "width: " + this.labelWidth + 'px';
29341 if(this.labelWidth < 13 && this.labelmd == 0){
29342 this.labelmd = this.labelWidth;
29345 if(this.labellg > 0){
29346 content[0].cls += ' col-lg-' + this.labellg;
29347 content[1].cls += ' col-lg-' + (12 - this.labellg);
29350 if(this.labelmd > 0){
29351 content[0].cls += ' col-md-' + this.labelmd;
29352 content[1].cls += ' col-md-' + (12 - this.labelmd);
29355 if(this.labelsm > 0){
29356 content[0].cls += ' col-sm-' + this.labelsm;
29357 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29360 if(this.labelxs > 0){
29361 content[0].cls += ' col-xs-' + this.labelxs;
29362 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29370 cls : 'row clearfix',
29378 initEvents : function()
29380 this.managerEl = this.el.select('.roo-document-manager', true).first();
29381 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29383 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29384 this.selectorEl.hide();
29387 this.selectorEl.attr('multiple', 'multiple');
29390 this.selectorEl.on('change', this.onFileSelected, this);
29392 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29393 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29395 this.uploader.on('click', this.onUploaderClick, this);
29397 this.renderProgressDialog();
29401 window.addEventListener("resize", function() { _this.refresh(); } );
29403 this.fireEvent('initial', this);
29406 renderProgressDialog : function()
29410 this.progressDialog = new Roo.bootstrap.Modal({
29411 cls : 'roo-document-manager-progress-dialog',
29412 allow_close : false,
29423 btnclick : function() {
29424 _this.uploadCancel();
29430 this.progressDialog.render(Roo.get(document.body));
29432 this.progress = new Roo.bootstrap.Progress({
29433 cls : 'roo-document-manager-progress',
29438 this.progress.render(this.progressDialog.getChildContainer());
29440 this.progressBar = new Roo.bootstrap.ProgressBar({
29441 cls : 'roo-document-manager-progress-bar',
29444 aria_valuemax : 12,
29448 this.progressBar.render(this.progress.getChildContainer());
29451 onUploaderClick : function(e)
29453 e.preventDefault();
29455 if(this.fireEvent('beforeselectfile', this) != false){
29456 this.selectorEl.dom.click();
29461 onFileSelected : function(e)
29463 e.preventDefault();
29465 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29469 Roo.each(this.selectorEl.dom.files, function(file){
29470 if(this.fireEvent('inspect', this, file) != false){
29471 this.files.push(file);
29481 this.selectorEl.dom.value = '';
29483 if(!this.files || !this.files.length){
29487 if(this.boxes > 0 && this.files.length > this.boxes){
29488 this.files = this.files.slice(0, this.boxes);
29491 this.uploader.show();
29493 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29494 this.uploader.hide();
29503 Roo.each(this.files, function(file){
29505 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29506 var f = this.renderPreview(file);
29511 if(file.type.indexOf('image') != -1){
29512 this.delegates.push(
29514 _this.process(file);
29515 }).createDelegate(this)
29523 _this.process(file);
29524 }).createDelegate(this)
29529 this.files = files;
29531 this.delegates = this.delegates.concat(docs);
29533 if(!this.delegates.length){
29538 this.progressBar.aria_valuemax = this.delegates.length;
29545 arrange : function()
29547 if(!this.delegates.length){
29548 this.progressDialog.hide();
29553 var delegate = this.delegates.shift();
29555 this.progressDialog.show();
29557 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29559 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29564 refresh : function()
29566 this.uploader.show();
29568 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29569 this.uploader.hide();
29572 Roo.isTouch ? this.closable(false) : this.closable(true);
29574 this.fireEvent('refresh', this);
29577 onRemove : function(e, el, o)
29579 e.preventDefault();
29581 this.fireEvent('remove', this, o);
29585 remove : function(o)
29589 Roo.each(this.files, function(file){
29590 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29599 this.files = files;
29606 Roo.each(this.files, function(file){
29611 file.target.remove();
29620 onClick : function(e, el, o)
29622 e.preventDefault();
29624 this.fireEvent('click', this, o);
29628 closable : function(closable)
29630 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29632 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29644 xhrOnLoad : function(xhr)
29646 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29650 if (xhr.readyState !== 4) {
29652 this.fireEvent('exception', this, xhr);
29656 var response = Roo.decode(xhr.responseText);
29658 if(!response.success){
29660 this.fireEvent('exception', this, xhr);
29664 var file = this.renderPreview(response.data);
29666 this.files.push(file);
29670 this.fireEvent('afterupload', this, xhr);
29674 xhrOnError : function(xhr)
29676 Roo.log('xhr on error');
29678 var response = Roo.decode(xhr.responseText);
29685 process : function(file)
29687 if(this.fireEvent('process', this, file) !== false){
29688 if(this.editable && file.type.indexOf('image') != -1){
29689 this.fireEvent('edit', this, file);
29693 this.uploadStart(file, false);
29700 uploadStart : function(file, crop)
29702 this.xhr = new XMLHttpRequest();
29704 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29709 file.xhr = this.xhr;
29711 this.managerEl.createChild({
29713 cls : 'roo-document-manager-loading',
29717 tooltip : file.name,
29718 cls : 'roo-document-manager-thumb',
29719 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29725 this.xhr.open(this.method, this.url, true);
29728 "Accept": "application/json",
29729 "Cache-Control": "no-cache",
29730 "X-Requested-With": "XMLHttpRequest"
29733 for (var headerName in headers) {
29734 var headerValue = headers[headerName];
29736 this.xhr.setRequestHeader(headerName, headerValue);
29742 this.xhr.onload = function()
29744 _this.xhrOnLoad(_this.xhr);
29747 this.xhr.onerror = function()
29749 _this.xhrOnError(_this.xhr);
29752 var formData = new FormData();
29754 formData.append('returnHTML', 'NO');
29757 formData.append('crop', crop);
29760 formData.append(this.paramName, file, file.name);
29767 if(this.fireEvent('prepare', this, formData, options) != false){
29769 if(options.manually){
29773 this.xhr.send(formData);
29777 this.uploadCancel();
29780 uploadCancel : function()
29786 this.delegates = [];
29788 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29795 renderPreview : function(file)
29797 if(typeof(file.target) != 'undefined' && file.target){
29801 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29803 var previewEl = this.managerEl.createChild({
29805 cls : 'roo-document-manager-preview',
29809 tooltip : file[this.toolTipName],
29810 cls : 'roo-document-manager-thumb',
29811 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29816 html : '<i class="fa fa-times-circle"></i>'
29821 var close = previewEl.select('button.close', true).first();
29823 close.on('click', this.onRemove, this, file);
29825 file.target = previewEl;
29827 var image = previewEl.select('img', true).first();
29831 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29833 image.on('click', this.onClick, this, file);
29835 this.fireEvent('previewrendered', this, file);
29841 onPreviewLoad : function(file, image)
29843 if(typeof(file.target) == 'undefined' || !file.target){
29847 var width = image.dom.naturalWidth || image.dom.width;
29848 var height = image.dom.naturalHeight || image.dom.height;
29850 if(!this.previewResize) {
29854 if(width > height){
29855 file.target.addClass('wide');
29859 file.target.addClass('tall');
29864 uploadFromSource : function(file, crop)
29866 this.xhr = new XMLHttpRequest();
29868 this.managerEl.createChild({
29870 cls : 'roo-document-manager-loading',
29874 tooltip : file.name,
29875 cls : 'roo-document-manager-thumb',
29876 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29882 this.xhr.open(this.method, this.url, true);
29885 "Accept": "application/json",
29886 "Cache-Control": "no-cache",
29887 "X-Requested-With": "XMLHttpRequest"
29890 for (var headerName in headers) {
29891 var headerValue = headers[headerName];
29893 this.xhr.setRequestHeader(headerName, headerValue);
29899 this.xhr.onload = function()
29901 _this.xhrOnLoad(_this.xhr);
29904 this.xhr.onerror = function()
29906 _this.xhrOnError(_this.xhr);
29909 var formData = new FormData();
29911 formData.append('returnHTML', 'NO');
29913 formData.append('crop', crop);
29915 if(typeof(file.filename) != 'undefined'){
29916 formData.append('filename', file.filename);
29919 if(typeof(file.mimetype) != 'undefined'){
29920 formData.append('mimetype', file.mimetype);
29925 if(this.fireEvent('prepare', this, formData) != false){
29926 this.xhr.send(formData);
29936 * @class Roo.bootstrap.DocumentViewer
29937 * @extends Roo.bootstrap.Component
29938 * Bootstrap DocumentViewer class
29939 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29940 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29943 * Create a new DocumentViewer
29944 * @param {Object} config The config object
29947 Roo.bootstrap.DocumentViewer = function(config){
29948 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29953 * Fire after initEvent
29954 * @param {Roo.bootstrap.DocumentViewer} this
29960 * @param {Roo.bootstrap.DocumentViewer} this
29965 * Fire after download button
29966 * @param {Roo.bootstrap.DocumentViewer} this
29971 * Fire after trash button
29972 * @param {Roo.bootstrap.DocumentViewer} this
29979 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29981 showDownload : true,
29985 getAutoCreate : function()
29989 cls : 'roo-document-viewer',
29993 cls : 'roo-document-viewer-body',
29997 cls : 'roo-document-viewer-thumb',
30001 cls : 'roo-document-viewer-image'
30009 cls : 'roo-document-viewer-footer',
30012 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30016 cls : 'btn-group roo-document-viewer-download',
30020 cls : 'btn btn-default',
30021 html : '<i class="fa fa-download"></i>'
30027 cls : 'btn-group roo-document-viewer-trash',
30031 cls : 'btn btn-default',
30032 html : '<i class="fa fa-trash"></i>'
30045 initEvents : function()
30047 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30048 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30050 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30051 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30053 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30054 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30056 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30057 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30059 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30060 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30062 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30063 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30065 this.bodyEl.on('click', this.onClick, this);
30066 this.downloadBtn.on('click', this.onDownload, this);
30067 this.trashBtn.on('click', this.onTrash, this);
30069 this.downloadBtn.hide();
30070 this.trashBtn.hide();
30072 if(this.showDownload){
30073 this.downloadBtn.show();
30076 if(this.showTrash){
30077 this.trashBtn.show();
30080 if(!this.showDownload && !this.showTrash) {
30081 this.footerEl.hide();
30086 initial : function()
30088 this.fireEvent('initial', this);
30092 onClick : function(e)
30094 e.preventDefault();
30096 this.fireEvent('click', this);
30099 onDownload : function(e)
30101 e.preventDefault();
30103 this.fireEvent('download', this);
30106 onTrash : function(e)
30108 e.preventDefault();
30110 this.fireEvent('trash', this);
30122 * @class Roo.bootstrap.NavProgressBar
30123 * @extends Roo.bootstrap.Component
30124 * Bootstrap NavProgressBar class
30127 * Create a new nav progress bar
30128 * @param {Object} config The config object
30131 Roo.bootstrap.NavProgressBar = function(config){
30132 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30134 this.bullets = this.bullets || [];
30136 // Roo.bootstrap.NavProgressBar.register(this);
30140 * Fires when the active item changes
30141 * @param {Roo.bootstrap.NavProgressBar} this
30142 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30143 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30150 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30155 getAutoCreate : function()
30157 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30161 cls : 'roo-navigation-bar-group',
30165 cls : 'roo-navigation-top-bar'
30169 cls : 'roo-navigation-bullets-bar',
30173 cls : 'roo-navigation-bar'
30180 cls : 'roo-navigation-bottom-bar'
30190 initEvents: function()
30195 onRender : function(ct, position)
30197 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30199 if(this.bullets.length){
30200 Roo.each(this.bullets, function(b){
30209 addItem : function(cfg)
30211 var item = new Roo.bootstrap.NavProgressItem(cfg);
30213 item.parentId = this.id;
30214 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30217 var top = new Roo.bootstrap.Element({
30219 cls : 'roo-navigation-bar-text'
30222 var bottom = new Roo.bootstrap.Element({
30224 cls : 'roo-navigation-bar-text'
30227 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30228 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30230 var topText = new Roo.bootstrap.Element({
30232 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30235 var bottomText = new Roo.bootstrap.Element({
30237 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30240 topText.onRender(top.el, null);
30241 bottomText.onRender(bottom.el, null);
30244 item.bottomEl = bottom;
30247 this.barItems.push(item);
30252 getActive : function()
30254 var active = false;
30256 Roo.each(this.barItems, function(v){
30258 if (!v.isActive()) {
30270 setActiveItem : function(item)
30274 Roo.each(this.barItems, function(v){
30275 if (v.rid == item.rid) {
30279 if (v.isActive()) {
30280 v.setActive(false);
30285 item.setActive(true);
30287 this.fireEvent('changed', this, item, prev);
30290 getBarItem: function(rid)
30294 Roo.each(this.barItems, function(e) {
30295 if (e.rid != rid) {
30306 indexOfItem : function(item)
30310 Roo.each(this.barItems, function(v, i){
30312 if (v.rid != item.rid) {
30323 setActiveNext : function()
30325 var i = this.indexOfItem(this.getActive());
30327 if (i > this.barItems.length) {
30331 this.setActiveItem(this.barItems[i+1]);
30334 setActivePrev : function()
30336 var i = this.indexOfItem(this.getActive());
30342 this.setActiveItem(this.barItems[i-1]);
30345 format : function()
30347 if(!this.barItems.length){
30351 var width = 100 / this.barItems.length;
30353 Roo.each(this.barItems, function(i){
30354 i.el.setStyle('width', width + '%');
30355 i.topEl.el.setStyle('width', width + '%');
30356 i.bottomEl.el.setStyle('width', width + '%');
30365 * Nav Progress Item
30370 * @class Roo.bootstrap.NavProgressItem
30371 * @extends Roo.bootstrap.Component
30372 * Bootstrap NavProgressItem class
30373 * @cfg {String} rid the reference id
30374 * @cfg {Boolean} active (true|false) Is item active default false
30375 * @cfg {Boolean} disabled (true|false) Is item active default false
30376 * @cfg {String} html
30377 * @cfg {String} position (top|bottom) text position default bottom
30378 * @cfg {String} icon show icon instead of number
30381 * Create a new NavProgressItem
30382 * @param {Object} config The config object
30384 Roo.bootstrap.NavProgressItem = function(config){
30385 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30390 * The raw click event for the entire grid.
30391 * @param {Roo.bootstrap.NavProgressItem} this
30392 * @param {Roo.EventObject} e
30399 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30405 position : 'bottom',
30408 getAutoCreate : function()
30410 var iconCls = 'roo-navigation-bar-item-icon';
30412 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30416 cls: 'roo-navigation-bar-item',
30426 cfg.cls += ' active';
30429 cfg.cls += ' disabled';
30435 disable : function()
30437 this.setDisabled(true);
30440 enable : function()
30442 this.setDisabled(false);
30445 initEvents: function()
30447 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30449 this.iconEl.on('click', this.onClick, this);
30452 onClick : function(e)
30454 e.preventDefault();
30460 if(this.fireEvent('click', this, e) === false){
30464 this.parent().setActiveItem(this);
30467 isActive: function ()
30469 return this.active;
30472 setActive : function(state)
30474 if(this.active == state){
30478 this.active = state;
30481 this.el.addClass('active');
30485 this.el.removeClass('active');
30490 setDisabled : function(state)
30492 if(this.disabled == state){
30496 this.disabled = state;
30499 this.el.addClass('disabled');
30503 this.el.removeClass('disabled');
30506 tooltipEl : function()
30508 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30521 * @class Roo.bootstrap.FieldLabel
30522 * @extends Roo.bootstrap.Component
30523 * Bootstrap FieldLabel class
30524 * @cfg {String} html contents of the element
30525 * @cfg {String} tag tag of the element default label
30526 * @cfg {String} cls class of the element
30527 * @cfg {String} target label target
30528 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30529 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30530 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30531 * @cfg {String} iconTooltip default "This field is required"
30532 * @cfg {String} indicatorpos (left|right) default left
30535 * Create a new FieldLabel
30536 * @param {Object} config The config object
30539 Roo.bootstrap.FieldLabel = function(config){
30540 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30545 * Fires after the field has been marked as invalid.
30546 * @param {Roo.form.FieldLabel} this
30547 * @param {String} msg The validation message
30552 * Fires after the field has been validated with no errors.
30553 * @param {Roo.form.FieldLabel} this
30559 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30566 invalidClass : 'has-warning',
30567 validClass : 'has-success',
30568 iconTooltip : 'This field is required',
30569 indicatorpos : 'left',
30571 getAutoCreate : function(){
30574 if (!this.allowBlank) {
30580 cls : 'roo-bootstrap-field-label ' + this.cls,
30585 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30586 tooltip : this.iconTooltip
30595 if(this.indicatorpos == 'right'){
30598 cls : 'roo-bootstrap-field-label ' + this.cls,
30607 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30608 tooltip : this.iconTooltip
30617 initEvents: function()
30619 Roo.bootstrap.Element.superclass.initEvents.call(this);
30621 this.indicator = this.indicatorEl();
30623 if(this.indicator){
30624 this.indicator.removeClass('visible');
30625 this.indicator.addClass('invisible');
30628 Roo.bootstrap.FieldLabel.register(this);
30631 indicatorEl : function()
30633 var indicator = this.el.select('i.roo-required-indicator',true).first();
30644 * Mark this field as valid
30646 markValid : function()
30648 if(this.indicator){
30649 this.indicator.removeClass('visible');
30650 this.indicator.addClass('invisible');
30652 if (Roo.bootstrap.version == 3) {
30653 this.el.removeClass(this.invalidClass);
30654 this.el.addClass(this.validClass);
30656 this.el.removeClass('is-invalid');
30657 this.el.addClass('is-valid');
30661 this.fireEvent('valid', this);
30665 * Mark this field as invalid
30666 * @param {String} msg The validation message
30668 markInvalid : function(msg)
30670 if(this.indicator){
30671 this.indicator.removeClass('invisible');
30672 this.indicator.addClass('visible');
30674 if (Roo.bootstrap.version == 3) {
30675 this.el.removeClass(this.validClass);
30676 this.el.addClass(this.invalidClass);
30678 this.el.removeClass('is-valid');
30679 this.el.addClass('is-invalid');
30683 this.fireEvent('invalid', this, msg);
30689 Roo.apply(Roo.bootstrap.FieldLabel, {
30694 * register a FieldLabel Group
30695 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30697 register : function(label)
30699 if(this.groups.hasOwnProperty(label.target)){
30703 this.groups[label.target] = label;
30707 * fetch a FieldLabel Group based on the target
30708 * @param {string} target
30709 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30711 get: function(target) {
30712 if (typeof(this.groups[target]) == 'undefined') {
30716 return this.groups[target] ;
30725 * page DateSplitField.
30731 * @class Roo.bootstrap.DateSplitField
30732 * @extends Roo.bootstrap.Component
30733 * Bootstrap DateSplitField class
30734 * @cfg {string} fieldLabel - the label associated
30735 * @cfg {Number} labelWidth set the width of label (0-12)
30736 * @cfg {String} labelAlign (top|left)
30737 * @cfg {Boolean} dayAllowBlank (true|false) default false
30738 * @cfg {Boolean} monthAllowBlank (true|false) default false
30739 * @cfg {Boolean} yearAllowBlank (true|false) default false
30740 * @cfg {string} dayPlaceholder
30741 * @cfg {string} monthPlaceholder
30742 * @cfg {string} yearPlaceholder
30743 * @cfg {string} dayFormat default 'd'
30744 * @cfg {string} monthFormat default 'm'
30745 * @cfg {string} yearFormat default 'Y'
30746 * @cfg {Number} labellg set the width of label (1-12)
30747 * @cfg {Number} labelmd set the width of label (1-12)
30748 * @cfg {Number} labelsm set the width of label (1-12)
30749 * @cfg {Number} labelxs set the width of label (1-12)
30753 * Create a new DateSplitField
30754 * @param {Object} config The config object
30757 Roo.bootstrap.DateSplitField = function(config){
30758 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30764 * getting the data of years
30765 * @param {Roo.bootstrap.DateSplitField} this
30766 * @param {Object} years
30771 * getting the data of days
30772 * @param {Roo.bootstrap.DateSplitField} this
30773 * @param {Object} days
30778 * Fires after the field has been marked as invalid.
30779 * @param {Roo.form.Field} this
30780 * @param {String} msg The validation message
30785 * Fires after the field has been validated with no errors.
30786 * @param {Roo.form.Field} this
30792 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30795 labelAlign : 'top',
30797 dayAllowBlank : false,
30798 monthAllowBlank : false,
30799 yearAllowBlank : false,
30800 dayPlaceholder : '',
30801 monthPlaceholder : '',
30802 yearPlaceholder : '',
30806 isFormField : true,
30812 getAutoCreate : function()
30816 cls : 'row roo-date-split-field-group',
30821 cls : 'form-hidden-field roo-date-split-field-group-value',
30827 var labelCls = 'col-md-12';
30828 var contentCls = 'col-md-4';
30830 if(this.fieldLabel){
30834 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30838 html : this.fieldLabel
30843 if(this.labelAlign == 'left'){
30845 if(this.labelWidth > 12){
30846 label.style = "width: " + this.labelWidth + 'px';
30849 if(this.labelWidth < 13 && this.labelmd == 0){
30850 this.labelmd = this.labelWidth;
30853 if(this.labellg > 0){
30854 labelCls = ' col-lg-' + this.labellg;
30855 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30858 if(this.labelmd > 0){
30859 labelCls = ' col-md-' + this.labelmd;
30860 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30863 if(this.labelsm > 0){
30864 labelCls = ' col-sm-' + this.labelsm;
30865 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30868 if(this.labelxs > 0){
30869 labelCls = ' col-xs-' + this.labelxs;
30870 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30874 label.cls += ' ' + labelCls;
30876 cfg.cn.push(label);
30879 Roo.each(['day', 'month', 'year'], function(t){
30882 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30889 inputEl: function ()
30891 return this.el.select('.roo-date-split-field-group-value', true).first();
30894 onRender : function(ct, position)
30898 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30900 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30902 this.dayField = new Roo.bootstrap.ComboBox({
30903 allowBlank : this.dayAllowBlank,
30904 alwaysQuery : true,
30905 displayField : 'value',
30908 forceSelection : true,
30910 placeholder : this.dayPlaceholder,
30911 selectOnFocus : true,
30912 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30913 triggerAction : 'all',
30915 valueField : 'value',
30916 store : new Roo.data.SimpleStore({
30917 data : (function() {
30919 _this.fireEvent('days', _this, days);
30922 fields : [ 'value' ]
30925 select : function (_self, record, index)
30927 _this.setValue(_this.getValue());
30932 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30934 this.monthField = new Roo.bootstrap.MonthField({
30935 after : '<i class=\"fa fa-calendar\"></i>',
30936 allowBlank : this.monthAllowBlank,
30937 placeholder : this.monthPlaceholder,
30940 render : function (_self)
30942 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30943 e.preventDefault();
30947 select : function (_self, oldvalue, newvalue)
30949 _this.setValue(_this.getValue());
30954 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30956 this.yearField = new Roo.bootstrap.ComboBox({
30957 allowBlank : this.yearAllowBlank,
30958 alwaysQuery : true,
30959 displayField : 'value',
30962 forceSelection : true,
30964 placeholder : this.yearPlaceholder,
30965 selectOnFocus : true,
30966 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30967 triggerAction : 'all',
30969 valueField : 'value',
30970 store : new Roo.data.SimpleStore({
30971 data : (function() {
30973 _this.fireEvent('years', _this, years);
30976 fields : [ 'value' ]
30979 select : function (_self, record, index)
30981 _this.setValue(_this.getValue());
30986 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30989 setValue : function(v, format)
30991 this.inputEl.dom.value = v;
30993 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30995 var d = Date.parseDate(v, f);
31002 this.setDay(d.format(this.dayFormat));
31003 this.setMonth(d.format(this.monthFormat));
31004 this.setYear(d.format(this.yearFormat));
31011 setDay : function(v)
31013 this.dayField.setValue(v);
31014 this.inputEl.dom.value = this.getValue();
31019 setMonth : function(v)
31021 this.monthField.setValue(v, true);
31022 this.inputEl.dom.value = this.getValue();
31027 setYear : function(v)
31029 this.yearField.setValue(v);
31030 this.inputEl.dom.value = this.getValue();
31035 getDay : function()
31037 return this.dayField.getValue();
31040 getMonth : function()
31042 return this.monthField.getValue();
31045 getYear : function()
31047 return this.yearField.getValue();
31050 getValue : function()
31052 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31054 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31064 this.inputEl.dom.value = '';
31069 validate : function()
31071 var d = this.dayField.validate();
31072 var m = this.monthField.validate();
31073 var y = this.yearField.validate();
31078 (!this.dayAllowBlank && !d) ||
31079 (!this.monthAllowBlank && !m) ||
31080 (!this.yearAllowBlank && !y)
31085 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31094 this.markInvalid();
31099 markValid : function()
31102 var label = this.el.select('label', true).first();
31103 var icon = this.el.select('i.fa-star', true).first();
31109 this.fireEvent('valid', this);
31113 * Mark this field as invalid
31114 * @param {String} msg The validation message
31116 markInvalid : function(msg)
31119 var label = this.el.select('label', true).first();
31120 var icon = this.el.select('i.fa-star', true).first();
31122 if(label && !icon){
31123 this.el.select('.roo-date-split-field-label', true).createChild({
31125 cls : 'text-danger fa fa-lg fa-star',
31126 tooltip : 'This field is required',
31127 style : 'margin-right:5px;'
31131 this.fireEvent('invalid', this, msg);
31134 clearInvalid : function()
31136 var label = this.el.select('label', true).first();
31137 var icon = this.el.select('i.fa-star', true).first();
31143 this.fireEvent('valid', this);
31146 getName: function()
31156 * http://masonry.desandro.com
31158 * The idea is to render all the bricks based on vertical width...
31160 * The original code extends 'outlayer' - we might need to use that....
31166 * @class Roo.bootstrap.LayoutMasonry
31167 * @extends Roo.bootstrap.Component
31168 * Bootstrap Layout Masonry class
31171 * Create a new Element
31172 * @param {Object} config The config object
31175 Roo.bootstrap.LayoutMasonry = function(config){
31177 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31181 Roo.bootstrap.LayoutMasonry.register(this);
31187 * Fire after layout the items
31188 * @param {Roo.bootstrap.LayoutMasonry} this
31189 * @param {Roo.EventObject} e
31196 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31199 * @cfg {Boolean} isLayoutInstant = no animation?
31201 isLayoutInstant : false, // needed?
31204 * @cfg {Number} boxWidth width of the columns
31209 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31214 * @cfg {Number} padWidth padding below box..
31219 * @cfg {Number} gutter gutter width..
31224 * @cfg {Number} maxCols maximum number of columns
31230 * @cfg {Boolean} isAutoInitial defalut true
31232 isAutoInitial : true,
31237 * @cfg {Boolean} isHorizontal defalut false
31239 isHorizontal : false,
31241 currentSize : null,
31247 bricks: null, //CompositeElement
31251 _isLayoutInited : false,
31253 // isAlternative : false, // only use for vertical layout...
31256 * @cfg {Number} alternativePadWidth padding below box..
31258 alternativePadWidth : 50,
31260 selectedBrick : [],
31262 getAutoCreate : function(){
31264 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31268 cls: 'blog-masonary-wrapper ' + this.cls,
31270 cls : 'mas-boxes masonary'
31277 getChildContainer: function( )
31279 if (this.boxesEl) {
31280 return this.boxesEl;
31283 this.boxesEl = this.el.select('.mas-boxes').first();
31285 return this.boxesEl;
31289 initEvents : function()
31293 if(this.isAutoInitial){
31294 Roo.log('hook children rendered');
31295 this.on('childrenrendered', function() {
31296 Roo.log('children rendered');
31302 initial : function()
31304 this.selectedBrick = [];
31306 this.currentSize = this.el.getBox(true);
31308 Roo.EventManager.onWindowResize(this.resize, this);
31310 if(!this.isAutoInitial){
31318 //this.layout.defer(500,this);
31322 resize : function()
31324 var cs = this.el.getBox(true);
31327 this.currentSize.width == cs.width &&
31328 this.currentSize.x == cs.x &&
31329 this.currentSize.height == cs.height &&
31330 this.currentSize.y == cs.y
31332 Roo.log("no change in with or X or Y");
31336 this.currentSize = cs;
31342 layout : function()
31344 this._resetLayout();
31346 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31348 this.layoutItems( isInstant );
31350 this._isLayoutInited = true;
31352 this.fireEvent('layout', this);
31356 _resetLayout : function()
31358 if(this.isHorizontal){
31359 this.horizontalMeasureColumns();
31363 this.verticalMeasureColumns();
31367 verticalMeasureColumns : function()
31369 this.getContainerWidth();
31371 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31372 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31376 var boxWidth = this.boxWidth + this.padWidth;
31378 if(this.containerWidth < this.boxWidth){
31379 boxWidth = this.containerWidth
31382 var containerWidth = this.containerWidth;
31384 var cols = Math.floor(containerWidth / boxWidth);
31386 this.cols = Math.max( cols, 1 );
31388 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31390 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31392 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31394 this.colWidth = boxWidth + avail - this.padWidth;
31396 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31397 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31400 horizontalMeasureColumns : function()
31402 this.getContainerWidth();
31404 var boxWidth = this.boxWidth;
31406 if(this.containerWidth < boxWidth){
31407 boxWidth = this.containerWidth;
31410 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31412 this.el.setHeight(boxWidth);
31416 getContainerWidth : function()
31418 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31421 layoutItems : function( isInstant )
31423 Roo.log(this.bricks);
31425 var items = Roo.apply([], this.bricks);
31427 if(this.isHorizontal){
31428 this._horizontalLayoutItems( items , isInstant );
31432 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31433 // this._verticalAlternativeLayoutItems( items , isInstant );
31437 this._verticalLayoutItems( items , isInstant );
31441 _verticalLayoutItems : function ( items , isInstant)
31443 if ( !items || !items.length ) {
31448 ['xs', 'xs', 'xs', 'tall'],
31449 ['xs', 'xs', 'tall'],
31450 ['xs', 'xs', 'sm'],
31451 ['xs', 'xs', 'xs'],
31457 ['sm', 'xs', 'xs'],
31461 ['tall', 'xs', 'xs', 'xs'],
31462 ['tall', 'xs', 'xs'],
31474 Roo.each(items, function(item, k){
31476 switch (item.size) {
31477 // these layouts take up a full box,
31488 boxes.push([item]);
31511 var filterPattern = function(box, length)
31519 var pattern = box.slice(0, length);
31523 Roo.each(pattern, function(i){
31524 format.push(i.size);
31527 Roo.each(standard, function(s){
31529 if(String(s) != String(format)){
31538 if(!match && length == 1){
31543 filterPattern(box, length - 1);
31547 queue.push(pattern);
31549 box = box.slice(length, box.length);
31551 filterPattern(box, 4);
31557 Roo.each(boxes, function(box, k){
31563 if(box.length == 1){
31568 filterPattern(box, 4);
31572 this._processVerticalLayoutQueue( queue, isInstant );
31576 // _verticalAlternativeLayoutItems : function( items , isInstant )
31578 // if ( !items || !items.length ) {
31582 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31586 _horizontalLayoutItems : function ( items , isInstant)
31588 if ( !items || !items.length || items.length < 3) {
31594 var eItems = items.slice(0, 3);
31596 items = items.slice(3, items.length);
31599 ['xs', 'xs', 'xs', 'wide'],
31600 ['xs', 'xs', 'wide'],
31601 ['xs', 'xs', 'sm'],
31602 ['xs', 'xs', 'xs'],
31608 ['sm', 'xs', 'xs'],
31612 ['wide', 'xs', 'xs', 'xs'],
31613 ['wide', 'xs', 'xs'],
31626 Roo.each(items, function(item, k){
31628 switch (item.size) {
31639 boxes.push([item]);
31663 var filterPattern = function(box, length)
31671 var pattern = box.slice(0, length);
31675 Roo.each(pattern, function(i){
31676 format.push(i.size);
31679 Roo.each(standard, function(s){
31681 if(String(s) != String(format)){
31690 if(!match && length == 1){
31695 filterPattern(box, length - 1);
31699 queue.push(pattern);
31701 box = box.slice(length, box.length);
31703 filterPattern(box, 4);
31709 Roo.each(boxes, function(box, k){
31715 if(box.length == 1){
31720 filterPattern(box, 4);
31727 var pos = this.el.getBox(true);
31731 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31733 var hit_end = false;
31735 Roo.each(queue, function(box){
31739 Roo.each(box, function(b){
31741 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31751 Roo.each(box, function(b){
31753 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31756 mx = Math.max(mx, b.x);
31760 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31764 Roo.each(box, function(b){
31766 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31780 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31783 /** Sets position of item in DOM
31784 * @param {Element} item
31785 * @param {Number} x - horizontal position
31786 * @param {Number} y - vertical position
31787 * @param {Boolean} isInstant - disables transitions
31789 _processVerticalLayoutQueue : function( queue, isInstant )
31791 var pos = this.el.getBox(true);
31796 for (var i = 0; i < this.cols; i++){
31800 Roo.each(queue, function(box, k){
31802 var col = k % this.cols;
31804 Roo.each(box, function(b,kk){
31806 b.el.position('absolute');
31808 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31809 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31811 if(b.size == 'md-left' || b.size == 'md-right'){
31812 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31813 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31816 b.el.setWidth(width);
31817 b.el.setHeight(height);
31819 b.el.select('iframe',true).setSize(width,height);
31823 for (var i = 0; i < this.cols; i++){
31825 if(maxY[i] < maxY[col]){
31830 col = Math.min(col, i);
31834 x = pos.x + col * (this.colWidth + this.padWidth);
31838 var positions = [];
31840 switch (box.length){
31842 positions = this.getVerticalOneBoxColPositions(x, y, box);
31845 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31848 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31851 positions = this.getVerticalFourBoxColPositions(x, y, box);
31857 Roo.each(box, function(b,kk){
31859 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31861 var sz = b.el.getSize();
31863 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31871 for (var i = 0; i < this.cols; i++){
31872 mY = Math.max(mY, maxY[i]);
31875 this.el.setHeight(mY - pos.y);
31879 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31881 // var pos = this.el.getBox(true);
31884 // var maxX = pos.right;
31886 // var maxHeight = 0;
31888 // Roo.each(items, function(item, k){
31892 // item.el.position('absolute');
31894 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31896 // item.el.setWidth(width);
31898 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31900 // item.el.setHeight(height);
31903 // item.el.setXY([x, y], isInstant ? false : true);
31905 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31908 // y = y + height + this.alternativePadWidth;
31910 // maxHeight = maxHeight + height + this.alternativePadWidth;
31914 // this.el.setHeight(maxHeight);
31918 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31920 var pos = this.el.getBox(true);
31925 var maxX = pos.right;
31927 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31929 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31931 Roo.each(queue, function(box, k){
31933 Roo.each(box, function(b, kk){
31935 b.el.position('absolute');
31937 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31938 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31940 if(b.size == 'md-left' || b.size == 'md-right'){
31941 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31942 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31945 b.el.setWidth(width);
31946 b.el.setHeight(height);
31954 var positions = [];
31956 switch (box.length){
31958 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31961 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31964 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31967 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31973 Roo.each(box, function(b,kk){
31975 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31977 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31985 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31987 Roo.each(eItems, function(b,k){
31989 b.size = (k == 0) ? 'sm' : 'xs';
31990 b.x = (k == 0) ? 2 : 1;
31991 b.y = (k == 0) ? 2 : 1;
31993 b.el.position('absolute');
31995 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31997 b.el.setWidth(width);
31999 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32001 b.el.setHeight(height);
32005 var positions = [];
32008 x : maxX - this.unitWidth * 2 - this.gutter,
32013 x : maxX - this.unitWidth,
32014 y : minY + (this.unitWidth + this.gutter) * 2
32018 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32022 Roo.each(eItems, function(b,k){
32024 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32030 getVerticalOneBoxColPositions : function(x, y, box)
32034 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32036 if(box[0].size == 'md-left'){
32040 if(box[0].size == 'md-right'){
32045 x : x + (this.unitWidth + this.gutter) * rand,
32052 getVerticalTwoBoxColPositions : function(x, y, box)
32056 if(box[0].size == 'xs'){
32060 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32064 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32078 x : x + (this.unitWidth + this.gutter) * 2,
32079 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32086 getVerticalThreeBoxColPositions : function(x, y, box)
32090 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32098 x : x + (this.unitWidth + this.gutter) * 1,
32103 x : x + (this.unitWidth + this.gutter) * 2,
32111 if(box[0].size == 'xs' && box[1].size == 'xs'){
32120 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32124 x : x + (this.unitWidth + this.gutter) * 1,
32138 x : x + (this.unitWidth + this.gutter) * 2,
32143 x : x + (this.unitWidth + this.gutter) * 2,
32144 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32151 getVerticalFourBoxColPositions : function(x, y, box)
32155 if(box[0].size == 'xs'){
32164 y : y + (this.unitHeight + this.gutter) * 1
32169 y : y + (this.unitHeight + this.gutter) * 2
32173 x : x + (this.unitWidth + this.gutter) * 1,
32187 x : x + (this.unitWidth + this.gutter) * 2,
32192 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32193 y : y + (this.unitHeight + this.gutter) * 1
32197 x : x + (this.unitWidth + this.gutter) * 2,
32198 y : y + (this.unitWidth + this.gutter) * 2
32205 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32209 if(box[0].size == 'md-left'){
32211 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32218 if(box[0].size == 'md-right'){
32220 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32221 y : minY + (this.unitWidth + this.gutter) * 1
32227 var rand = Math.floor(Math.random() * (4 - box[0].y));
32230 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32231 y : minY + (this.unitWidth + this.gutter) * rand
32238 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32242 if(box[0].size == 'xs'){
32245 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32250 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32251 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32259 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32264 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32265 y : minY + (this.unitWidth + this.gutter) * 2
32272 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32276 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32279 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32284 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32285 y : minY + (this.unitWidth + this.gutter) * 1
32289 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32290 y : minY + (this.unitWidth + this.gutter) * 2
32297 if(box[0].size == 'xs' && box[1].size == 'xs'){
32300 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32305 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32310 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32311 y : minY + (this.unitWidth + this.gutter) * 1
32319 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32324 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32325 y : minY + (this.unitWidth + this.gutter) * 2
32329 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32330 y : minY + (this.unitWidth + this.gutter) * 2
32337 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32341 if(box[0].size == 'xs'){
32344 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32349 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32354 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),
32359 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32360 y : minY + (this.unitWidth + this.gutter) * 1
32368 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32373 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32374 y : minY + (this.unitWidth + this.gutter) * 2
32378 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32379 y : minY + (this.unitWidth + this.gutter) * 2
32383 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),
32384 y : minY + (this.unitWidth + this.gutter) * 2
32392 * remove a Masonry Brick
32393 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32395 removeBrick : function(brick_id)
32401 for (var i = 0; i<this.bricks.length; i++) {
32402 if (this.bricks[i].id == brick_id) {
32403 this.bricks.splice(i,1);
32404 this.el.dom.removeChild(Roo.get(brick_id).dom);
32411 * adds a Masonry Brick
32412 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32414 addBrick : function(cfg)
32416 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32417 //this.register(cn);
32418 cn.parentId = this.id;
32419 cn.render(this.el);
32424 * register a Masonry Brick
32425 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32428 register : function(brick)
32430 this.bricks.push(brick);
32431 brick.masonryId = this.id;
32435 * clear all the Masonry Brick
32437 clearAll : function()
32440 //this.getChildContainer().dom.innerHTML = "";
32441 this.el.dom.innerHTML = '';
32444 getSelected : function()
32446 if (!this.selectedBrick) {
32450 return this.selectedBrick;
32454 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32458 * register a Masonry Layout
32459 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32462 register : function(layout)
32464 this.groups[layout.id] = layout;
32467 * fetch a Masonry Layout based on the masonry layout ID
32468 * @param {string} the masonry layout to add
32469 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32472 get: function(layout_id) {
32473 if (typeof(this.groups[layout_id]) == 'undefined') {
32476 return this.groups[layout_id] ;
32488 * http://masonry.desandro.com
32490 * The idea is to render all the bricks based on vertical width...
32492 * The original code extends 'outlayer' - we might need to use that....
32498 * @class Roo.bootstrap.LayoutMasonryAuto
32499 * @extends Roo.bootstrap.Component
32500 * Bootstrap Layout Masonry class
32503 * Create a new Element
32504 * @param {Object} config The config object
32507 Roo.bootstrap.LayoutMasonryAuto = function(config){
32508 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32511 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32514 * @cfg {Boolean} isFitWidth - resize the width..
32516 isFitWidth : false, // options..
32518 * @cfg {Boolean} isOriginLeft = left align?
32520 isOriginLeft : true,
32522 * @cfg {Boolean} isOriginTop = top align?
32524 isOriginTop : false,
32526 * @cfg {Boolean} isLayoutInstant = no animation?
32528 isLayoutInstant : false, // needed?
32530 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32532 isResizingContainer : true,
32534 * @cfg {Number} columnWidth width of the columns
32540 * @cfg {Number} maxCols maximum number of columns
32545 * @cfg {Number} padHeight padding below box..
32551 * @cfg {Boolean} isAutoInitial defalut true
32554 isAutoInitial : true,
32560 initialColumnWidth : 0,
32561 currentSize : null,
32563 colYs : null, // array.
32570 bricks: null, //CompositeElement
32571 cols : 0, // array?
32572 // element : null, // wrapped now this.el
32573 _isLayoutInited : null,
32576 getAutoCreate : function(){
32580 cls: 'blog-masonary-wrapper ' + this.cls,
32582 cls : 'mas-boxes masonary'
32589 getChildContainer: function( )
32591 if (this.boxesEl) {
32592 return this.boxesEl;
32595 this.boxesEl = this.el.select('.mas-boxes').first();
32597 return this.boxesEl;
32601 initEvents : function()
32605 if(this.isAutoInitial){
32606 Roo.log('hook children rendered');
32607 this.on('childrenrendered', function() {
32608 Roo.log('children rendered');
32615 initial : function()
32617 this.reloadItems();
32619 this.currentSize = this.el.getBox(true);
32621 /// was window resize... - let's see if this works..
32622 Roo.EventManager.onWindowResize(this.resize, this);
32624 if(!this.isAutoInitial){
32629 this.layout.defer(500,this);
32632 reloadItems: function()
32634 this.bricks = this.el.select('.masonry-brick', true);
32636 this.bricks.each(function(b) {
32637 //Roo.log(b.getSize());
32638 if (!b.attr('originalwidth')) {
32639 b.attr('originalwidth', b.getSize().width);
32644 Roo.log(this.bricks.elements.length);
32647 resize : function()
32650 var cs = this.el.getBox(true);
32652 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32653 Roo.log("no change in with or X");
32656 this.currentSize = cs;
32660 layout : function()
32663 this._resetLayout();
32664 //this._manageStamps();
32666 // don't animate first layout
32667 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32668 this.layoutItems( isInstant );
32670 // flag for initalized
32671 this._isLayoutInited = true;
32674 layoutItems : function( isInstant )
32676 //var items = this._getItemsForLayout( this.items );
32677 // original code supports filtering layout items.. we just ignore it..
32679 this._layoutItems( this.bricks , isInstant );
32681 this._postLayout();
32683 _layoutItems : function ( items , isInstant)
32685 //this.fireEvent( 'layout', this, items );
32688 if ( !items || !items.elements.length ) {
32689 // no items, emit event with empty array
32694 items.each(function(item) {
32695 Roo.log("layout item");
32697 // get x/y object from method
32698 var position = this._getItemLayoutPosition( item );
32700 position.item = item;
32701 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32702 queue.push( position );
32705 this._processLayoutQueue( queue );
32707 /** Sets position of item in DOM
32708 * @param {Element} item
32709 * @param {Number} x - horizontal position
32710 * @param {Number} y - vertical position
32711 * @param {Boolean} isInstant - disables transitions
32713 _processLayoutQueue : function( queue )
32715 for ( var i=0, len = queue.length; i < len; i++ ) {
32716 var obj = queue[i];
32717 obj.item.position('absolute');
32718 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32724 * Any logic you want to do after each layout,
32725 * i.e. size the container
32727 _postLayout : function()
32729 this.resizeContainer();
32732 resizeContainer : function()
32734 if ( !this.isResizingContainer ) {
32737 var size = this._getContainerSize();
32739 this.el.setSize(size.width,size.height);
32740 this.boxesEl.setSize(size.width,size.height);
32746 _resetLayout : function()
32748 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32749 this.colWidth = this.el.getWidth();
32750 //this.gutter = this.el.getWidth();
32752 this.measureColumns();
32758 this.colYs.push( 0 );
32764 measureColumns : function()
32766 this.getContainerWidth();
32767 // if columnWidth is 0, default to outerWidth of first item
32768 if ( !this.columnWidth ) {
32769 var firstItem = this.bricks.first();
32770 Roo.log(firstItem);
32771 this.columnWidth = this.containerWidth;
32772 if (firstItem && firstItem.attr('originalwidth') ) {
32773 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32775 // columnWidth fall back to item of first element
32776 Roo.log("set column width?");
32777 this.initialColumnWidth = this.columnWidth ;
32779 // if first elem has no width, default to size of container
32784 if (this.initialColumnWidth) {
32785 this.columnWidth = this.initialColumnWidth;
32790 // column width is fixed at the top - however if container width get's smaller we should
32793 // this bit calcs how man columns..
32795 var columnWidth = this.columnWidth += this.gutter;
32797 // calculate columns
32798 var containerWidth = this.containerWidth + this.gutter;
32800 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32801 // fix rounding errors, typically with gutters
32802 var excess = columnWidth - containerWidth % columnWidth;
32805 // if overshoot is less than a pixel, round up, otherwise floor it
32806 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32807 cols = Math[ mathMethod ]( cols );
32808 this.cols = Math.max( cols, 1 );
32809 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32811 // padding positioning..
32812 var totalColWidth = this.cols * this.columnWidth;
32813 var padavail = this.containerWidth - totalColWidth;
32814 // so for 2 columns - we need 3 'pads'
32816 var padNeeded = (1+this.cols) * this.padWidth;
32818 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32820 this.columnWidth += padExtra
32821 //this.padWidth = Math.floor(padavail / ( this.cols));
32823 // adjust colum width so that padding is fixed??
32825 // we have 3 columns ... total = width * 3
32826 // we have X left over... that should be used by
32828 //if (this.expandC) {
32836 getContainerWidth : function()
32838 /* // container is parent if fit width
32839 var container = this.isFitWidth ? this.element.parentNode : this.element;
32840 // check that this.size and size are there
32841 // IE8 triggers resize on body size change, so they might not be
32843 var size = getSize( container ); //FIXME
32844 this.containerWidth = size && size.innerWidth; //FIXME
32847 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32851 _getItemLayoutPosition : function( item ) // what is item?
32853 // we resize the item to our columnWidth..
32855 item.setWidth(this.columnWidth);
32856 item.autoBoxAdjust = false;
32858 var sz = item.getSize();
32860 // how many columns does this brick span
32861 var remainder = this.containerWidth % this.columnWidth;
32863 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32864 // round if off by 1 pixel, otherwise use ceil
32865 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32866 colSpan = Math.min( colSpan, this.cols );
32868 // normally this should be '1' as we dont' currently allow multi width columns..
32870 var colGroup = this._getColGroup( colSpan );
32871 // get the minimum Y value from the columns
32872 var minimumY = Math.min.apply( Math, colGroup );
32873 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32875 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32877 // position the brick
32879 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32880 y: this.currentSize.y + minimumY + this.padHeight
32884 // apply setHeight to necessary columns
32885 var setHeight = minimumY + sz.height + this.padHeight;
32886 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32888 var setSpan = this.cols + 1 - colGroup.length;
32889 for ( var i = 0; i < setSpan; i++ ) {
32890 this.colYs[ shortColIndex + i ] = setHeight ;
32897 * @param {Number} colSpan - number of columns the element spans
32898 * @returns {Array} colGroup
32900 _getColGroup : function( colSpan )
32902 if ( colSpan < 2 ) {
32903 // if brick spans only one column, use all the column Ys
32908 // how many different places could this brick fit horizontally
32909 var groupCount = this.cols + 1 - colSpan;
32910 // for each group potential horizontal position
32911 for ( var i = 0; i < groupCount; i++ ) {
32912 // make an array of colY values for that one group
32913 var groupColYs = this.colYs.slice( i, i + colSpan );
32914 // and get the max value of the array
32915 colGroup[i] = Math.max.apply( Math, groupColYs );
32920 _manageStamp : function( stamp )
32922 var stampSize = stamp.getSize();
32923 var offset = stamp.getBox();
32924 // get the columns that this stamp affects
32925 var firstX = this.isOriginLeft ? offset.x : offset.right;
32926 var lastX = firstX + stampSize.width;
32927 var firstCol = Math.floor( firstX / this.columnWidth );
32928 firstCol = Math.max( 0, firstCol );
32930 var lastCol = Math.floor( lastX / this.columnWidth );
32931 // lastCol should not go over if multiple of columnWidth #425
32932 lastCol -= lastX % this.columnWidth ? 0 : 1;
32933 lastCol = Math.min( this.cols - 1, lastCol );
32935 // set colYs to bottom of the stamp
32936 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32939 for ( var i = firstCol; i <= lastCol; i++ ) {
32940 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32945 _getContainerSize : function()
32947 this.maxY = Math.max.apply( Math, this.colYs );
32952 if ( this.isFitWidth ) {
32953 size.width = this._getContainerFitWidth();
32959 _getContainerFitWidth : function()
32961 var unusedCols = 0;
32962 // count unused columns
32965 if ( this.colYs[i] !== 0 ) {
32970 // fit container to columns that have been used
32971 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32974 needsResizeLayout : function()
32976 var previousWidth = this.containerWidth;
32977 this.getContainerWidth();
32978 return previousWidth !== this.containerWidth;
32993 * @class Roo.bootstrap.MasonryBrick
32994 * @extends Roo.bootstrap.Component
32995 * Bootstrap MasonryBrick class
32998 * Create a new MasonryBrick
32999 * @param {Object} config The config object
33002 Roo.bootstrap.MasonryBrick = function(config){
33004 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
33006 Roo.bootstrap.MasonryBrick.register(this);
33012 * When a MasonryBrick is clcik
33013 * @param {Roo.bootstrap.MasonryBrick} this
33014 * @param {Roo.EventObject} e
33020 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33023 * @cfg {String} title
33027 * @cfg {String} html
33031 * @cfg {String} bgimage
33035 * @cfg {String} videourl
33039 * @cfg {String} cls
33043 * @cfg {String} href
33047 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33052 * @cfg {String} placetitle (center|bottom)
33057 * @cfg {Boolean} isFitContainer defalut true
33059 isFitContainer : true,
33062 * @cfg {Boolean} preventDefault defalut false
33064 preventDefault : false,
33067 * @cfg {Boolean} inverse defalut false
33069 maskInverse : false,
33071 getAutoCreate : function()
33073 if(!this.isFitContainer){
33074 return this.getSplitAutoCreate();
33077 var cls = 'masonry-brick masonry-brick-full';
33079 if(this.href.length){
33080 cls += ' masonry-brick-link';
33083 if(this.bgimage.length){
33084 cls += ' masonry-brick-image';
33087 if(this.maskInverse){
33088 cls += ' mask-inverse';
33091 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33092 cls += ' enable-mask';
33096 cls += ' masonry-' + this.size + '-brick';
33099 if(this.placetitle.length){
33101 switch (this.placetitle) {
33103 cls += ' masonry-center-title';
33106 cls += ' masonry-bottom-title';
33113 if(!this.html.length && !this.bgimage.length){
33114 cls += ' masonry-center-title';
33117 if(!this.html.length && this.bgimage.length){
33118 cls += ' masonry-bottom-title';
33123 cls += ' ' + this.cls;
33127 tag: (this.href.length) ? 'a' : 'div',
33132 cls: 'masonry-brick-mask'
33136 cls: 'masonry-brick-paragraph',
33142 if(this.href.length){
33143 cfg.href = this.href;
33146 var cn = cfg.cn[1].cn;
33148 if(this.title.length){
33151 cls: 'masonry-brick-title',
33156 if(this.html.length){
33159 cls: 'masonry-brick-text',
33164 if (!this.title.length && !this.html.length) {
33165 cfg.cn[1].cls += ' hide';
33168 if(this.bgimage.length){
33171 cls: 'masonry-brick-image-view',
33176 if(this.videourl.length){
33177 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33178 // youtube support only?
33181 cls: 'masonry-brick-image-view',
33184 allowfullscreen : true
33192 getSplitAutoCreate : function()
33194 var cls = 'masonry-brick masonry-brick-split';
33196 if(this.href.length){
33197 cls += ' masonry-brick-link';
33200 if(this.bgimage.length){
33201 cls += ' masonry-brick-image';
33205 cls += ' masonry-' + this.size + '-brick';
33208 switch (this.placetitle) {
33210 cls += ' masonry-center-title';
33213 cls += ' masonry-bottom-title';
33216 if(!this.bgimage.length){
33217 cls += ' masonry-center-title';
33220 if(this.bgimage.length){
33221 cls += ' masonry-bottom-title';
33227 cls += ' ' + this.cls;
33231 tag: (this.href.length) ? 'a' : 'div',
33236 cls: 'masonry-brick-split-head',
33240 cls: 'masonry-brick-paragraph',
33247 cls: 'masonry-brick-split-body',
33253 if(this.href.length){
33254 cfg.href = this.href;
33257 if(this.title.length){
33258 cfg.cn[0].cn[0].cn.push({
33260 cls: 'masonry-brick-title',
33265 if(this.html.length){
33266 cfg.cn[1].cn.push({
33268 cls: 'masonry-brick-text',
33273 if(this.bgimage.length){
33274 cfg.cn[0].cn.push({
33276 cls: 'masonry-brick-image-view',
33281 if(this.videourl.length){
33282 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33283 // youtube support only?
33284 cfg.cn[0].cn.cn.push({
33286 cls: 'masonry-brick-image-view',
33289 allowfullscreen : true
33296 initEvents: function()
33298 switch (this.size) {
33331 this.el.on('touchstart', this.onTouchStart, this);
33332 this.el.on('touchmove', this.onTouchMove, this);
33333 this.el.on('touchend', this.onTouchEnd, this);
33334 this.el.on('contextmenu', this.onContextMenu, this);
33336 this.el.on('mouseenter' ,this.enter, this);
33337 this.el.on('mouseleave', this.leave, this);
33338 this.el.on('click', this.onClick, this);
33341 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33342 this.parent().bricks.push(this);
33347 onClick: function(e, el)
33349 var time = this.endTimer - this.startTimer;
33350 // Roo.log(e.preventDefault());
33353 e.preventDefault();
33358 if(!this.preventDefault){
33362 e.preventDefault();
33364 if (this.activeClass != '') {
33365 this.selectBrick();
33368 this.fireEvent('click', this, e);
33371 enter: function(e, el)
33373 e.preventDefault();
33375 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33379 if(this.bgimage.length && this.html.length){
33380 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33384 leave: function(e, el)
33386 e.preventDefault();
33388 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33392 if(this.bgimage.length && this.html.length){
33393 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33397 onTouchStart: function(e, el)
33399 // e.preventDefault();
33401 this.touchmoved = false;
33403 if(!this.isFitContainer){
33407 if(!this.bgimage.length || !this.html.length){
33411 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33413 this.timer = new Date().getTime();
33417 onTouchMove: function(e, el)
33419 this.touchmoved = true;
33422 onContextMenu : function(e,el)
33424 e.preventDefault();
33425 e.stopPropagation();
33429 onTouchEnd: function(e, el)
33431 // e.preventDefault();
33433 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33440 if(!this.bgimage.length || !this.html.length){
33442 if(this.href.length){
33443 window.location.href = this.href;
33449 if(!this.isFitContainer){
33453 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33455 window.location.href = this.href;
33458 //selection on single brick only
33459 selectBrick : function() {
33461 if (!this.parentId) {
33465 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33466 var index = m.selectedBrick.indexOf(this.id);
33469 m.selectedBrick.splice(index,1);
33470 this.el.removeClass(this.activeClass);
33474 for(var i = 0; i < m.selectedBrick.length; i++) {
33475 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33476 b.el.removeClass(b.activeClass);
33479 m.selectedBrick = [];
33481 m.selectedBrick.push(this.id);
33482 this.el.addClass(this.activeClass);
33486 isSelected : function(){
33487 return this.el.hasClass(this.activeClass);
33492 Roo.apply(Roo.bootstrap.MasonryBrick, {
33495 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33497 * register a Masonry Brick
33498 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33501 register : function(brick)
33503 //this.groups[brick.id] = brick;
33504 this.groups.add(brick.id, brick);
33507 * fetch a masonry brick based on the masonry brick ID
33508 * @param {string} the masonry brick to add
33509 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33512 get: function(brick_id)
33514 // if (typeof(this.groups[brick_id]) == 'undefined') {
33517 // return this.groups[brick_id] ;
33519 if(this.groups.key(brick_id)) {
33520 return this.groups.key(brick_id);
33538 * @class Roo.bootstrap.Brick
33539 * @extends Roo.bootstrap.Component
33540 * Bootstrap Brick class
33543 * Create a new Brick
33544 * @param {Object} config The config object
33547 Roo.bootstrap.Brick = function(config){
33548 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33554 * When a Brick is click
33555 * @param {Roo.bootstrap.Brick} this
33556 * @param {Roo.EventObject} e
33562 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33565 * @cfg {String} title
33569 * @cfg {String} html
33573 * @cfg {String} bgimage
33577 * @cfg {String} cls
33581 * @cfg {String} href
33585 * @cfg {String} video
33589 * @cfg {Boolean} square
33593 getAutoCreate : function()
33595 var cls = 'roo-brick';
33597 if(this.href.length){
33598 cls += ' roo-brick-link';
33601 if(this.bgimage.length){
33602 cls += ' roo-brick-image';
33605 if(!this.html.length && !this.bgimage.length){
33606 cls += ' roo-brick-center-title';
33609 if(!this.html.length && this.bgimage.length){
33610 cls += ' roo-brick-bottom-title';
33614 cls += ' ' + this.cls;
33618 tag: (this.href.length) ? 'a' : 'div',
33623 cls: 'roo-brick-paragraph',
33629 if(this.href.length){
33630 cfg.href = this.href;
33633 var cn = cfg.cn[0].cn;
33635 if(this.title.length){
33638 cls: 'roo-brick-title',
33643 if(this.html.length){
33646 cls: 'roo-brick-text',
33653 if(this.bgimage.length){
33656 cls: 'roo-brick-image-view',
33664 initEvents: function()
33666 if(this.title.length || this.html.length){
33667 this.el.on('mouseenter' ,this.enter, this);
33668 this.el.on('mouseleave', this.leave, this);
33671 Roo.EventManager.onWindowResize(this.resize, this);
33673 if(this.bgimage.length){
33674 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33675 this.imageEl.on('load', this.onImageLoad, this);
33682 onImageLoad : function()
33687 resize : function()
33689 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33691 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33693 if(this.bgimage.length){
33694 var image = this.el.select('.roo-brick-image-view', true).first();
33696 image.setWidth(paragraph.getWidth());
33699 image.setHeight(paragraph.getWidth());
33702 this.el.setHeight(image.getHeight());
33703 paragraph.setHeight(image.getHeight());
33709 enter: function(e, el)
33711 e.preventDefault();
33713 if(this.bgimage.length){
33714 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33715 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33719 leave: function(e, el)
33721 e.preventDefault();
33723 if(this.bgimage.length){
33724 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33725 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33740 * @class Roo.bootstrap.NumberField
33741 * @extends Roo.bootstrap.Input
33742 * Bootstrap NumberField class
33748 * Create a new NumberField
33749 * @param {Object} config The config object
33752 Roo.bootstrap.NumberField = function(config){
33753 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33756 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33759 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33761 allowDecimals : true,
33763 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33765 decimalSeparator : ".",
33767 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33769 decimalPrecision : 2,
33771 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33773 allowNegative : true,
33776 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33780 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33782 minValue : Number.NEGATIVE_INFINITY,
33784 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33786 maxValue : Number.MAX_VALUE,
33788 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33790 minText : "The minimum value for this field is {0}",
33792 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33794 maxText : "The maximum value for this field is {0}",
33796 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33797 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33799 nanText : "{0} is not a valid number",
33801 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33803 thousandsDelimiter : false,
33805 * @cfg {String} valueAlign alignment of value
33807 valueAlign : "left",
33809 getAutoCreate : function()
33811 var hiddenInput = {
33815 cls: 'hidden-number-input'
33819 hiddenInput.name = this.name;
33824 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33826 this.name = hiddenInput.name;
33828 if(cfg.cn.length > 0) {
33829 cfg.cn.push(hiddenInput);
33836 initEvents : function()
33838 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33840 var allowed = "0123456789";
33842 if(this.allowDecimals){
33843 allowed += this.decimalSeparator;
33846 if(this.allowNegative){
33850 if(this.thousandsDelimiter) {
33854 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33856 var keyPress = function(e){
33858 var k = e.getKey();
33860 var c = e.getCharCode();
33863 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33864 allowed.indexOf(String.fromCharCode(c)) === -1
33870 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33874 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33879 this.el.on("keypress", keyPress, this);
33882 validateValue : function(value)
33885 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33889 var num = this.parseValue(value);
33892 this.markInvalid(String.format(this.nanText, value));
33896 if(num < this.minValue){
33897 this.markInvalid(String.format(this.minText, this.minValue));
33901 if(num > this.maxValue){
33902 this.markInvalid(String.format(this.maxText, this.maxValue));
33909 getValue : function()
33911 var v = this.hiddenEl().getValue();
33913 return this.fixPrecision(this.parseValue(v));
33916 parseValue : function(value)
33918 if(this.thousandsDelimiter) {
33920 r = new RegExp(",", "g");
33921 value = value.replace(r, "");
33924 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33925 return isNaN(value) ? '' : value;
33928 fixPrecision : function(value)
33930 if(this.thousandsDelimiter) {
33932 r = new RegExp(",", "g");
33933 value = value.replace(r, "");
33936 var nan = isNaN(value);
33938 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33939 return nan ? '' : value;
33941 return parseFloat(value).toFixed(this.decimalPrecision);
33944 setValue : function(v)
33946 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33952 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33954 this.inputEl().dom.value = (v == '') ? '' :
33955 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33957 if(!this.allowZero && v === '0') {
33958 this.hiddenEl().dom.value = '';
33959 this.inputEl().dom.value = '';
33966 decimalPrecisionFcn : function(v)
33968 return Math.floor(v);
33971 beforeBlur : function()
33973 var v = this.parseValue(this.getRawValue());
33975 if(v || v === 0 || v === ''){
33980 hiddenEl : function()
33982 return this.el.select('input.hidden-number-input',true).first();
33994 * @class Roo.bootstrap.DocumentSlider
33995 * @extends Roo.bootstrap.Component
33996 * Bootstrap DocumentSlider class
33999 * Create a new DocumentViewer
34000 * @param {Object} config The config object
34003 Roo.bootstrap.DocumentSlider = function(config){
34004 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34011 * Fire after initEvent
34012 * @param {Roo.bootstrap.DocumentSlider} this
34017 * Fire after update
34018 * @param {Roo.bootstrap.DocumentSlider} this
34024 * @param {Roo.bootstrap.DocumentSlider} this
34030 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34036 getAutoCreate : function()
34040 cls : 'roo-document-slider',
34044 cls : 'roo-document-slider-header',
34048 cls : 'roo-document-slider-header-title'
34054 cls : 'roo-document-slider-body',
34058 cls : 'roo-document-slider-prev',
34062 cls : 'fa fa-chevron-left'
34068 cls : 'roo-document-slider-thumb',
34072 cls : 'roo-document-slider-image'
34078 cls : 'roo-document-slider-next',
34082 cls : 'fa fa-chevron-right'
34094 initEvents : function()
34096 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34097 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34099 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34100 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34102 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34103 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34105 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34106 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34108 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34109 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34111 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34112 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34114 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34115 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34117 this.thumbEl.on('click', this.onClick, this);
34119 this.prevIndicator.on('click', this.prev, this);
34121 this.nextIndicator.on('click', this.next, this);
34125 initial : function()
34127 if(this.files.length){
34128 this.indicator = 1;
34132 this.fireEvent('initial', this);
34135 update : function()
34137 this.imageEl.attr('src', this.files[this.indicator - 1]);
34139 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34141 this.prevIndicator.show();
34143 if(this.indicator == 1){
34144 this.prevIndicator.hide();
34147 this.nextIndicator.show();
34149 if(this.indicator == this.files.length){
34150 this.nextIndicator.hide();
34153 this.thumbEl.scrollTo('top');
34155 this.fireEvent('update', this);
34158 onClick : function(e)
34160 e.preventDefault();
34162 this.fireEvent('click', this);
34167 e.preventDefault();
34169 this.indicator = Math.max(1, this.indicator - 1);
34176 e.preventDefault();
34178 this.indicator = Math.min(this.files.length, this.indicator + 1);
34192 * @class Roo.bootstrap.RadioSet
34193 * @extends Roo.bootstrap.Input
34194 * Bootstrap RadioSet class
34195 * @cfg {String} indicatorpos (left|right) default left
34196 * @cfg {Boolean} inline (true|false) inline the element (default true)
34197 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34199 * Create a new RadioSet
34200 * @param {Object} config The config object
34203 Roo.bootstrap.RadioSet = function(config){
34205 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34209 Roo.bootstrap.RadioSet.register(this);
34214 * Fires when the element is checked or unchecked.
34215 * @param {Roo.bootstrap.RadioSet} this This radio
34216 * @param {Roo.bootstrap.Radio} item The checked item
34221 * Fires when the element is click.
34222 * @param {Roo.bootstrap.RadioSet} this This radio set
34223 * @param {Roo.bootstrap.Radio} item The checked item
34224 * @param {Roo.EventObject} e The event object
34231 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34239 indicatorpos : 'left',
34241 getAutoCreate : function()
34245 cls : 'roo-radio-set-label',
34249 html : this.fieldLabel
34253 if (Roo.bootstrap.version == 3) {
34256 if(this.indicatorpos == 'left'){
34259 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34260 tooltip : 'This field is required'
34265 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34266 tooltip : 'This field is required'
34272 cls : 'roo-radio-set-items'
34275 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34277 if (align === 'left' && this.fieldLabel.length) {
34280 cls : "roo-radio-set-right",
34286 if(this.labelWidth > 12){
34287 label.style = "width: " + this.labelWidth + 'px';
34290 if(this.labelWidth < 13 && this.labelmd == 0){
34291 this.labelmd = this.labelWidth;
34294 if(this.labellg > 0){
34295 label.cls += ' col-lg-' + this.labellg;
34296 items.cls += ' col-lg-' + (12 - this.labellg);
34299 if(this.labelmd > 0){
34300 label.cls += ' col-md-' + this.labelmd;
34301 items.cls += ' col-md-' + (12 - this.labelmd);
34304 if(this.labelsm > 0){
34305 label.cls += ' col-sm-' + this.labelsm;
34306 items.cls += ' col-sm-' + (12 - this.labelsm);
34309 if(this.labelxs > 0){
34310 label.cls += ' col-xs-' + this.labelxs;
34311 items.cls += ' col-xs-' + (12 - this.labelxs);
34317 cls : 'roo-radio-set',
34321 cls : 'roo-radio-set-input',
34324 value : this.value ? this.value : ''
34331 if(this.weight.length){
34332 cfg.cls += ' roo-radio-' + this.weight;
34336 cfg.cls += ' roo-radio-set-inline';
34340 ['xs','sm','md','lg'].map(function(size){
34341 if (settings[size]) {
34342 cfg.cls += ' col-' + size + '-' + settings[size];
34350 initEvents : function()
34352 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34353 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34355 if(!this.fieldLabel.length){
34356 this.labelEl.hide();
34359 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34360 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34362 this.indicator = this.indicatorEl();
34364 if(this.indicator){
34365 this.indicator.addClass('invisible');
34368 this.originalValue = this.getValue();
34372 inputEl: function ()
34374 return this.el.select('.roo-radio-set-input', true).first();
34377 getChildContainer : function()
34379 return this.itemsEl;
34382 register : function(item)
34384 this.radioes.push(item);
34388 validate : function()
34390 if(this.getVisibilityEl().hasClass('hidden')){
34396 Roo.each(this.radioes, function(i){
34405 if(this.allowBlank) {
34409 if(this.disabled || valid){
34414 this.markInvalid();
34419 markValid : function()
34421 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34422 this.indicatorEl().removeClass('visible');
34423 this.indicatorEl().addClass('invisible');
34427 if (Roo.bootstrap.version == 3) {
34428 this.el.removeClass([this.invalidClass, this.validClass]);
34429 this.el.addClass(this.validClass);
34431 this.el.removeClass(['is-invalid','is-valid']);
34432 this.el.addClass(['is-valid']);
34434 this.fireEvent('valid', this);
34437 markInvalid : function(msg)
34439 if(this.allowBlank || this.disabled){
34443 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34444 this.indicatorEl().removeClass('invisible');
34445 this.indicatorEl().addClass('visible');
34447 if (Roo.bootstrap.version == 3) {
34448 this.el.removeClass([this.invalidClass, this.validClass]);
34449 this.el.addClass(this.invalidClass);
34451 this.el.removeClass(['is-invalid','is-valid']);
34452 this.el.addClass(['is-invalid']);
34455 this.fireEvent('invalid', this, msg);
34459 setValue : function(v, suppressEvent)
34461 if(this.value === v){
34468 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34471 Roo.each(this.radioes, function(i){
34473 i.el.removeClass('checked');
34476 Roo.each(this.radioes, function(i){
34478 if(i.value === v || i.value.toString() === v.toString()){
34480 i.el.addClass('checked');
34482 if(suppressEvent !== true){
34483 this.fireEvent('check', this, i);
34494 clearInvalid : function(){
34496 if(!this.el || this.preventMark){
34500 this.el.removeClass([this.invalidClass]);
34502 this.fireEvent('valid', this);
34507 Roo.apply(Roo.bootstrap.RadioSet, {
34511 register : function(set)
34513 this.groups[set.name] = set;
34516 get: function(name)
34518 if (typeof(this.groups[name]) == 'undefined') {
34522 return this.groups[name] ;
34528 * Ext JS Library 1.1.1
34529 * Copyright(c) 2006-2007, Ext JS, LLC.
34531 * Originally Released Under LGPL - original licence link has changed is not relivant.
34534 * <script type="text/javascript">
34539 * @class Roo.bootstrap.SplitBar
34540 * @extends Roo.util.Observable
34541 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34545 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34546 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34547 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34548 split.minSize = 100;
34549 split.maxSize = 600;
34550 split.animate = true;
34551 split.on('moved', splitterMoved);
34554 * Create a new SplitBar
34555 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34556 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34557 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34558 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34559 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34560 position of the SplitBar).
34562 Roo.bootstrap.SplitBar = function(cfg){
34567 // dragElement : elm
34568 // resizingElement: el,
34570 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34571 // placement : Roo.bootstrap.SplitBar.LEFT ,
34572 // existingProxy ???
34575 this.el = Roo.get(cfg.dragElement, true);
34576 this.el.dom.unselectable = "on";
34578 this.resizingEl = Roo.get(cfg.resizingElement, true);
34582 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34583 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34586 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34589 * The minimum size of the resizing element. (Defaults to 0)
34595 * The maximum size of the resizing element. (Defaults to 2000)
34598 this.maxSize = 2000;
34601 * Whether to animate the transition to the new size
34604 this.animate = false;
34607 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34610 this.useShim = false;
34615 if(!cfg.existingProxy){
34617 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34619 this.proxy = Roo.get(cfg.existingProxy).dom;
34622 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34625 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34628 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34631 this.dragSpecs = {};
34634 * @private The adapter to use to positon and resize elements
34636 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34637 this.adapter.init(this);
34639 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34641 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34642 this.el.addClass("roo-splitbar-h");
34645 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34646 this.el.addClass("roo-splitbar-v");
34652 * Fires when the splitter is moved (alias for {@link #event-moved})
34653 * @param {Roo.bootstrap.SplitBar} this
34654 * @param {Number} newSize the new width or height
34659 * Fires when the splitter is moved
34660 * @param {Roo.bootstrap.SplitBar} this
34661 * @param {Number} newSize the new width or height
34665 * @event beforeresize
34666 * Fires before the splitter is dragged
34667 * @param {Roo.bootstrap.SplitBar} this
34669 "beforeresize" : true,
34671 "beforeapply" : true
34674 Roo.util.Observable.call(this);
34677 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34678 onStartProxyDrag : function(x, y){
34679 this.fireEvent("beforeresize", this);
34681 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34683 o.enableDisplayMode("block");
34684 // all splitbars share the same overlay
34685 Roo.bootstrap.SplitBar.prototype.overlay = o;
34687 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34688 this.overlay.show();
34689 Roo.get(this.proxy).setDisplayed("block");
34690 var size = this.adapter.getElementSize(this);
34691 this.activeMinSize = this.getMinimumSize();;
34692 this.activeMaxSize = this.getMaximumSize();;
34693 var c1 = size - this.activeMinSize;
34694 var c2 = Math.max(this.activeMaxSize - size, 0);
34695 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34696 this.dd.resetConstraints();
34697 this.dd.setXConstraint(
34698 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34699 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34701 this.dd.setYConstraint(0, 0);
34703 this.dd.resetConstraints();
34704 this.dd.setXConstraint(0, 0);
34705 this.dd.setYConstraint(
34706 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34707 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34710 this.dragSpecs.startSize = size;
34711 this.dragSpecs.startPoint = [x, y];
34712 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34716 * @private Called after the drag operation by the DDProxy
34718 onEndProxyDrag : function(e){
34719 Roo.get(this.proxy).setDisplayed(false);
34720 var endPoint = Roo.lib.Event.getXY(e);
34722 this.overlay.hide();
34725 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34726 newSize = this.dragSpecs.startSize +
34727 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34728 endPoint[0] - this.dragSpecs.startPoint[0] :
34729 this.dragSpecs.startPoint[0] - endPoint[0]
34732 newSize = this.dragSpecs.startSize +
34733 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34734 endPoint[1] - this.dragSpecs.startPoint[1] :
34735 this.dragSpecs.startPoint[1] - endPoint[1]
34738 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34739 if(newSize != this.dragSpecs.startSize){
34740 if(this.fireEvent('beforeapply', this, newSize) !== false){
34741 this.adapter.setElementSize(this, newSize);
34742 this.fireEvent("moved", this, newSize);
34743 this.fireEvent("resize", this, newSize);
34749 * Get the adapter this SplitBar uses
34750 * @return The adapter object
34752 getAdapter : function(){
34753 return this.adapter;
34757 * Set the adapter this SplitBar uses
34758 * @param {Object} adapter A SplitBar adapter object
34760 setAdapter : function(adapter){
34761 this.adapter = adapter;
34762 this.adapter.init(this);
34766 * Gets the minimum size for the resizing element
34767 * @return {Number} The minimum size
34769 getMinimumSize : function(){
34770 return this.minSize;
34774 * Sets the minimum size for the resizing element
34775 * @param {Number} minSize The minimum size
34777 setMinimumSize : function(minSize){
34778 this.minSize = minSize;
34782 * Gets the maximum size for the resizing element
34783 * @return {Number} The maximum size
34785 getMaximumSize : function(){
34786 return this.maxSize;
34790 * Sets the maximum size for the resizing element
34791 * @param {Number} maxSize The maximum size
34793 setMaximumSize : function(maxSize){
34794 this.maxSize = maxSize;
34798 * Sets the initialize size for the resizing element
34799 * @param {Number} size The initial size
34801 setCurrentSize : function(size){
34802 var oldAnimate = this.animate;
34803 this.animate = false;
34804 this.adapter.setElementSize(this, size);
34805 this.animate = oldAnimate;
34809 * Destroy this splitbar.
34810 * @param {Boolean} removeEl True to remove the element
34812 destroy : function(removeEl){
34814 this.shim.remove();
34817 this.proxy.parentNode.removeChild(this.proxy);
34825 * @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.
34827 Roo.bootstrap.SplitBar.createProxy = function(dir){
34828 var proxy = new Roo.Element(document.createElement("div"));
34829 proxy.unselectable();
34830 var cls = 'roo-splitbar-proxy';
34831 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34832 document.body.appendChild(proxy.dom);
34837 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34838 * Default Adapter. It assumes the splitter and resizing element are not positioned
34839 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34841 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34844 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34845 // do nothing for now
34846 init : function(s){
34850 * Called before drag operations to get the current size of the resizing element.
34851 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34853 getElementSize : function(s){
34854 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34855 return s.resizingEl.getWidth();
34857 return s.resizingEl.getHeight();
34862 * Called after drag operations to set the size of the resizing element.
34863 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34864 * @param {Number} newSize The new size to set
34865 * @param {Function} onComplete A function to be invoked when resizing is complete
34867 setElementSize : function(s, newSize, onComplete){
34868 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34870 s.resizingEl.setWidth(newSize);
34872 onComplete(s, newSize);
34875 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34880 s.resizingEl.setHeight(newSize);
34882 onComplete(s, newSize);
34885 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34892 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34893 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34894 * Adapter that moves the splitter element to align with the resized sizing element.
34895 * Used with an absolute positioned SplitBar.
34896 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34897 * document.body, make sure you assign an id to the body element.
34899 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34900 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34901 this.container = Roo.get(container);
34904 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34905 init : function(s){
34906 this.basic.init(s);
34909 getElementSize : function(s){
34910 return this.basic.getElementSize(s);
34913 setElementSize : function(s, newSize, onComplete){
34914 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34917 moveSplitter : function(s){
34918 var yes = Roo.bootstrap.SplitBar;
34919 switch(s.placement){
34921 s.el.setX(s.resizingEl.getRight());
34924 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34927 s.el.setY(s.resizingEl.getBottom());
34930 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34937 * Orientation constant - Create a vertical SplitBar
34941 Roo.bootstrap.SplitBar.VERTICAL = 1;
34944 * Orientation constant - Create a horizontal SplitBar
34948 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34951 * Placement constant - The resizing element is to the left of the splitter element
34955 Roo.bootstrap.SplitBar.LEFT = 1;
34958 * Placement constant - The resizing element is to the right of the splitter element
34962 Roo.bootstrap.SplitBar.RIGHT = 2;
34965 * Placement constant - The resizing element is positioned above the splitter element
34969 Roo.bootstrap.SplitBar.TOP = 3;
34972 * Placement constant - The resizing element is positioned under splitter element
34976 Roo.bootstrap.SplitBar.BOTTOM = 4;
34977 Roo.namespace("Roo.bootstrap.layout");/*
34979 * Ext JS Library 1.1.1
34980 * Copyright(c) 2006-2007, Ext JS, LLC.
34982 * Originally Released Under LGPL - original licence link has changed is not relivant.
34985 * <script type="text/javascript">
34989 * @class Roo.bootstrap.layout.Manager
34990 * @extends Roo.bootstrap.Component
34991 * Base class for layout managers.
34993 Roo.bootstrap.layout.Manager = function(config)
34995 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
35001 /** false to disable window resize monitoring @type Boolean */
35002 this.monitorWindowResize = true;
35007 * Fires when a layout is performed.
35008 * @param {Roo.LayoutManager} this
35012 * @event regionresized
35013 * Fires when the user resizes a region.
35014 * @param {Roo.LayoutRegion} region The resized region
35015 * @param {Number} newSize The new size (width for east/west, height for north/south)
35017 "regionresized" : true,
35019 * @event regioncollapsed
35020 * Fires when a region is collapsed.
35021 * @param {Roo.LayoutRegion} region The collapsed region
35023 "regioncollapsed" : true,
35025 * @event regionexpanded
35026 * Fires when a region is expanded.
35027 * @param {Roo.LayoutRegion} region The expanded region
35029 "regionexpanded" : true
35031 this.updating = false;
35034 this.el = Roo.get(config.el);
35040 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35045 monitorWindowResize : true,
35051 onRender : function(ct, position)
35054 this.el = Roo.get(ct);
35057 //this.fireEvent('render',this);
35061 initEvents: function()
35065 // ie scrollbar fix
35066 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35067 document.body.scroll = "no";
35068 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35069 this.el.position('relative');
35071 this.id = this.el.id;
35072 this.el.addClass("roo-layout-container");
35073 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35074 if(this.el.dom != document.body ) {
35075 this.el.on('resize', this.layout,this);
35076 this.el.on('show', this.layout,this);
35082 * Returns true if this layout is currently being updated
35083 * @return {Boolean}
35085 isUpdating : function(){
35086 return this.updating;
35090 * Suspend the LayoutManager from doing auto-layouts while
35091 * making multiple add or remove calls
35093 beginUpdate : function(){
35094 this.updating = true;
35098 * Restore auto-layouts and optionally disable the manager from performing a layout
35099 * @param {Boolean} noLayout true to disable a layout update
35101 endUpdate : function(noLayout){
35102 this.updating = false;
35108 layout: function(){
35112 onRegionResized : function(region, newSize){
35113 this.fireEvent("regionresized", region, newSize);
35117 onRegionCollapsed : function(region){
35118 this.fireEvent("regioncollapsed", region);
35121 onRegionExpanded : function(region){
35122 this.fireEvent("regionexpanded", region);
35126 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35127 * performs box-model adjustments.
35128 * @return {Object} The size as an object {width: (the width), height: (the height)}
35130 getViewSize : function()
35133 if(this.el.dom != document.body){
35134 size = this.el.getSize();
35136 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35138 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35139 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35144 * Returns the Element this layout is bound to.
35145 * @return {Roo.Element}
35147 getEl : function(){
35152 * Returns the specified region.
35153 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35154 * @return {Roo.LayoutRegion}
35156 getRegion : function(target){
35157 return this.regions[target.toLowerCase()];
35160 onWindowResize : function(){
35161 if(this.monitorWindowResize){
35168 * Ext JS Library 1.1.1
35169 * Copyright(c) 2006-2007, Ext JS, LLC.
35171 * Originally Released Under LGPL - original licence link has changed is not relivant.
35174 * <script type="text/javascript">
35177 * @class Roo.bootstrap.layout.Border
35178 * @extends Roo.bootstrap.layout.Manager
35179 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35180 * please see: examples/bootstrap/nested.html<br><br>
35182 <b>The container the layout is rendered into can be either the body element or any other element.
35183 If it is not the body element, the container needs to either be an absolute positioned element,
35184 or you will need to add "position:relative" to the css of the container. You will also need to specify
35185 the container size if it is not the body element.</b>
35188 * Create a new Border
35189 * @param {Object} config Configuration options
35191 Roo.bootstrap.layout.Border = function(config){
35192 config = config || {};
35193 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35197 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35198 if(config[region]){
35199 config[region].region = region;
35200 this.addRegion(config[region]);
35206 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35208 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35210 parent : false, // this might point to a 'nest' or a ???
35213 * Creates and adds a new region if it doesn't already exist.
35214 * @param {String} target The target region key (north, south, east, west or center).
35215 * @param {Object} config The regions config object
35216 * @return {BorderLayoutRegion} The new region
35218 addRegion : function(config)
35220 if(!this.regions[config.region]){
35221 var r = this.factory(config);
35222 this.bindRegion(r);
35224 return this.regions[config.region];
35228 bindRegion : function(r){
35229 this.regions[r.config.region] = r;
35231 r.on("visibilitychange", this.layout, this);
35232 r.on("paneladded", this.layout, this);
35233 r.on("panelremoved", this.layout, this);
35234 r.on("invalidated", this.layout, this);
35235 r.on("resized", this.onRegionResized, this);
35236 r.on("collapsed", this.onRegionCollapsed, this);
35237 r.on("expanded", this.onRegionExpanded, this);
35241 * Performs a layout update.
35243 layout : function()
35245 if(this.updating) {
35249 // render all the rebions if they have not been done alreayd?
35250 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35251 if(this.regions[region] && !this.regions[region].bodyEl){
35252 this.regions[region].onRender(this.el)
35256 var size = this.getViewSize();
35257 var w = size.width;
35258 var h = size.height;
35263 //var x = 0, y = 0;
35265 var rs = this.regions;
35266 var north = rs["north"];
35267 var south = rs["south"];
35268 var west = rs["west"];
35269 var east = rs["east"];
35270 var center = rs["center"];
35271 //if(this.hideOnLayout){ // not supported anymore
35272 //c.el.setStyle("display", "none");
35274 if(north && north.isVisible()){
35275 var b = north.getBox();
35276 var m = north.getMargins();
35277 b.width = w - (m.left+m.right);
35280 centerY = b.height + b.y + m.bottom;
35281 centerH -= centerY;
35282 north.updateBox(this.safeBox(b));
35284 if(south && south.isVisible()){
35285 var b = south.getBox();
35286 var m = south.getMargins();
35287 b.width = w - (m.left+m.right);
35289 var totalHeight = (b.height + m.top + m.bottom);
35290 b.y = h - totalHeight + m.top;
35291 centerH -= totalHeight;
35292 south.updateBox(this.safeBox(b));
35294 if(west && west.isVisible()){
35295 var b = west.getBox();
35296 var m = west.getMargins();
35297 b.height = centerH - (m.top+m.bottom);
35299 b.y = centerY + m.top;
35300 var totalWidth = (b.width + m.left + m.right);
35301 centerX += totalWidth;
35302 centerW -= totalWidth;
35303 west.updateBox(this.safeBox(b));
35305 if(east && east.isVisible()){
35306 var b = east.getBox();
35307 var m = east.getMargins();
35308 b.height = centerH - (m.top+m.bottom);
35309 var totalWidth = (b.width + m.left + m.right);
35310 b.x = w - totalWidth + m.left;
35311 b.y = centerY + m.top;
35312 centerW -= totalWidth;
35313 east.updateBox(this.safeBox(b));
35316 var m = center.getMargins();
35318 x: centerX + m.left,
35319 y: centerY + m.top,
35320 width: centerW - (m.left+m.right),
35321 height: centerH - (m.top+m.bottom)
35323 //if(this.hideOnLayout){
35324 //center.el.setStyle("display", "block");
35326 center.updateBox(this.safeBox(centerBox));
35329 this.fireEvent("layout", this);
35333 safeBox : function(box){
35334 box.width = Math.max(0, box.width);
35335 box.height = Math.max(0, box.height);
35340 * Adds a ContentPanel (or subclass) to this layout.
35341 * @param {String} target The target region key (north, south, east, west or center).
35342 * @param {Roo.ContentPanel} panel The panel to add
35343 * @return {Roo.ContentPanel} The added panel
35345 add : function(target, panel){
35347 target = target.toLowerCase();
35348 return this.regions[target].add(panel);
35352 * Remove a ContentPanel (or subclass) to this layout.
35353 * @param {String} target The target region key (north, south, east, west or center).
35354 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35355 * @return {Roo.ContentPanel} The removed panel
35357 remove : function(target, panel){
35358 target = target.toLowerCase();
35359 return this.regions[target].remove(panel);
35363 * Searches all regions for a panel with the specified id
35364 * @param {String} panelId
35365 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35367 findPanel : function(panelId){
35368 var rs = this.regions;
35369 for(var target in rs){
35370 if(typeof rs[target] != "function"){
35371 var p = rs[target].getPanel(panelId);
35381 * Searches all regions for a panel with the specified id and activates (shows) it.
35382 * @param {String/ContentPanel} panelId The panels id or the panel itself
35383 * @return {Roo.ContentPanel} The shown panel or null
35385 showPanel : function(panelId) {
35386 var rs = this.regions;
35387 for(var target in rs){
35388 var r = rs[target];
35389 if(typeof r != "function"){
35390 if(r.hasPanel(panelId)){
35391 return r.showPanel(panelId);
35399 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35400 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35403 restoreState : function(provider){
35405 provider = Roo.state.Manager;
35407 var sm = new Roo.LayoutStateManager();
35408 sm.init(this, provider);
35414 * Adds a xtype elements to the layout.
35418 xtype : 'ContentPanel',
35425 xtype : 'NestedLayoutPanel',
35431 items : [ ... list of content panels or nested layout panels.. ]
35435 * @param {Object} cfg Xtype definition of item to add.
35437 addxtype : function(cfg)
35439 // basically accepts a pannel...
35440 // can accept a layout region..!?!?
35441 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35444 // theory? children can only be panels??
35446 //if (!cfg.xtype.match(/Panel$/)) {
35451 if (typeof(cfg.region) == 'undefined') {
35452 Roo.log("Failed to add Panel, region was not set");
35456 var region = cfg.region;
35462 xitems = cfg.items;
35467 if ( region == 'center') {
35468 Roo.log("Center: " + cfg.title);
35474 case 'Content': // ContentPanel (el, cfg)
35475 case 'Scroll': // ContentPanel (el, cfg)
35477 cfg.autoCreate = cfg.autoCreate || true;
35478 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35480 // var el = this.el.createChild();
35481 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35484 this.add(region, ret);
35488 case 'TreePanel': // our new panel!
35489 cfg.el = this.el.createChild();
35490 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35491 this.add(region, ret);
35496 // create a new Layout (which is a Border Layout...
35498 var clayout = cfg.layout;
35499 clayout.el = this.el.createChild();
35500 clayout.items = clayout.items || [];
35504 // replace this exitems with the clayout ones..
35505 xitems = clayout.items;
35507 // force background off if it's in center...
35508 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35509 cfg.background = false;
35511 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35514 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35515 //console.log('adding nested layout panel ' + cfg.toSource());
35516 this.add(region, ret);
35517 nb = {}; /// find first...
35522 // needs grid and region
35524 //var el = this.getRegion(region).el.createChild();
35526 *var el = this.el.createChild();
35527 // create the grid first...
35528 cfg.grid.container = el;
35529 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35532 if (region == 'center' && this.active ) {
35533 cfg.background = false;
35536 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35538 this.add(region, ret);
35540 if (cfg.background) {
35541 // render grid on panel activation (if panel background)
35542 ret.on('activate', function(gp) {
35543 if (!gp.grid.rendered) {
35544 // gp.grid.render(el);
35548 // cfg.grid.render(el);
35554 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35555 // it was the old xcomponent building that caused this before.
35556 // espeically if border is the top element in the tree.
35566 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35568 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35569 this.add(region, ret);
35573 throw "Can not add '" + cfg.xtype + "' to Border";
35579 this.beginUpdate();
35583 Roo.each(xitems, function(i) {
35584 region = nb && i.region ? i.region : false;
35586 var add = ret.addxtype(i);
35589 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35590 if (!i.background) {
35591 abn[region] = nb[region] ;
35598 // make the last non-background panel active..
35599 //if (nb) { Roo.log(abn); }
35602 for(var r in abn) {
35603 region = this.getRegion(r);
35605 // tried using nb[r], but it does not work..
35607 region.showPanel(abn[r]);
35618 factory : function(cfg)
35621 var validRegions = Roo.bootstrap.layout.Border.regions;
35623 var target = cfg.region;
35626 var r = Roo.bootstrap.layout;
35630 return new r.North(cfg);
35632 return new r.South(cfg);
35634 return new r.East(cfg);
35636 return new r.West(cfg);
35638 return new r.Center(cfg);
35640 throw 'Layout region "'+target+'" not supported.';
35647 * Ext JS Library 1.1.1
35648 * Copyright(c) 2006-2007, Ext JS, LLC.
35650 * Originally Released Under LGPL - original licence link has changed is not relivant.
35653 * <script type="text/javascript">
35657 * @class Roo.bootstrap.layout.Basic
35658 * @extends Roo.util.Observable
35659 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35660 * and does not have a titlebar, tabs or any other features. All it does is size and position
35661 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35662 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35663 * @cfg {string} region the region that it inhabits..
35664 * @cfg {bool} skipConfig skip config?
35668 Roo.bootstrap.layout.Basic = function(config){
35670 this.mgr = config.mgr;
35672 this.position = config.region;
35674 var skipConfig = config.skipConfig;
35678 * @scope Roo.BasicLayoutRegion
35682 * @event beforeremove
35683 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35684 * @param {Roo.LayoutRegion} this
35685 * @param {Roo.ContentPanel} panel The panel
35686 * @param {Object} e The cancel event object
35688 "beforeremove" : true,
35690 * @event invalidated
35691 * Fires when the layout for this region is changed.
35692 * @param {Roo.LayoutRegion} this
35694 "invalidated" : true,
35696 * @event visibilitychange
35697 * Fires when this region is shown or hidden
35698 * @param {Roo.LayoutRegion} this
35699 * @param {Boolean} visibility true or false
35701 "visibilitychange" : true,
35703 * @event paneladded
35704 * Fires when a panel is added.
35705 * @param {Roo.LayoutRegion} this
35706 * @param {Roo.ContentPanel} panel The panel
35708 "paneladded" : true,
35710 * @event panelremoved
35711 * Fires when a panel is removed.
35712 * @param {Roo.LayoutRegion} this
35713 * @param {Roo.ContentPanel} panel The panel
35715 "panelremoved" : true,
35717 * @event beforecollapse
35718 * Fires when this region before collapse.
35719 * @param {Roo.LayoutRegion} this
35721 "beforecollapse" : true,
35724 * Fires when this region is collapsed.
35725 * @param {Roo.LayoutRegion} this
35727 "collapsed" : true,
35730 * Fires when this region is expanded.
35731 * @param {Roo.LayoutRegion} this
35736 * Fires when this region is slid into view.
35737 * @param {Roo.LayoutRegion} this
35739 "slideshow" : true,
35742 * Fires when this region slides out of view.
35743 * @param {Roo.LayoutRegion} this
35745 "slidehide" : true,
35747 * @event panelactivated
35748 * Fires when a panel is activated.
35749 * @param {Roo.LayoutRegion} this
35750 * @param {Roo.ContentPanel} panel The activated panel
35752 "panelactivated" : true,
35755 * Fires when the user resizes this region.
35756 * @param {Roo.LayoutRegion} this
35757 * @param {Number} newSize The new size (width for east/west, height for north/south)
35761 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35762 this.panels = new Roo.util.MixedCollection();
35763 this.panels.getKey = this.getPanelId.createDelegate(this);
35765 this.activePanel = null;
35766 // ensure listeners are added...
35768 if (config.listeners || config.events) {
35769 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35770 listeners : config.listeners || {},
35771 events : config.events || {}
35775 if(skipConfig !== true){
35776 this.applyConfig(config);
35780 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35782 getPanelId : function(p){
35786 applyConfig : function(config){
35787 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35788 this.config = config;
35793 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35794 * the width, for horizontal (north, south) the height.
35795 * @param {Number} newSize The new width or height
35797 resizeTo : function(newSize){
35798 var el = this.el ? this.el :
35799 (this.activePanel ? this.activePanel.getEl() : null);
35801 switch(this.position){
35804 el.setWidth(newSize);
35805 this.fireEvent("resized", this, newSize);
35809 el.setHeight(newSize);
35810 this.fireEvent("resized", this, newSize);
35816 getBox : function(){
35817 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35820 getMargins : function(){
35821 return this.margins;
35824 updateBox : function(box){
35826 var el = this.activePanel.getEl();
35827 el.dom.style.left = box.x + "px";
35828 el.dom.style.top = box.y + "px";
35829 this.activePanel.setSize(box.width, box.height);
35833 * Returns the container element for this region.
35834 * @return {Roo.Element}
35836 getEl : function(){
35837 return this.activePanel;
35841 * Returns true if this region is currently visible.
35842 * @return {Boolean}
35844 isVisible : function(){
35845 return this.activePanel ? true : false;
35848 setActivePanel : function(panel){
35849 panel = this.getPanel(panel);
35850 if(this.activePanel && this.activePanel != panel){
35851 this.activePanel.setActiveState(false);
35852 this.activePanel.getEl().setLeftTop(-10000,-10000);
35854 this.activePanel = panel;
35855 panel.setActiveState(true);
35857 panel.setSize(this.box.width, this.box.height);
35859 this.fireEvent("panelactivated", this, panel);
35860 this.fireEvent("invalidated");
35864 * Show the specified panel.
35865 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35866 * @return {Roo.ContentPanel} The shown panel or null
35868 showPanel : function(panel){
35869 panel = this.getPanel(panel);
35871 this.setActivePanel(panel);
35877 * Get the active panel for this region.
35878 * @return {Roo.ContentPanel} The active panel or null
35880 getActivePanel : function(){
35881 return this.activePanel;
35885 * Add the passed ContentPanel(s)
35886 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35887 * @return {Roo.ContentPanel} The panel added (if only one was added)
35889 add : function(panel){
35890 if(arguments.length > 1){
35891 for(var i = 0, len = arguments.length; i < len; i++) {
35892 this.add(arguments[i]);
35896 if(this.hasPanel(panel)){
35897 this.showPanel(panel);
35900 var el = panel.getEl();
35901 if(el.dom.parentNode != this.mgr.el.dom){
35902 this.mgr.el.dom.appendChild(el.dom);
35904 if(panel.setRegion){
35905 panel.setRegion(this);
35907 this.panels.add(panel);
35908 el.setStyle("position", "absolute");
35909 if(!panel.background){
35910 this.setActivePanel(panel);
35911 if(this.config.initialSize && this.panels.getCount()==1){
35912 this.resizeTo(this.config.initialSize);
35915 this.fireEvent("paneladded", this, panel);
35920 * Returns true if the panel is in this region.
35921 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35922 * @return {Boolean}
35924 hasPanel : function(panel){
35925 if(typeof panel == "object"){ // must be panel obj
35926 panel = panel.getId();
35928 return this.getPanel(panel) ? true : false;
35932 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35933 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35934 * @param {Boolean} preservePanel Overrides the config preservePanel option
35935 * @return {Roo.ContentPanel} The panel that was removed
35937 remove : function(panel, preservePanel){
35938 panel = this.getPanel(panel);
35943 this.fireEvent("beforeremove", this, panel, e);
35944 if(e.cancel === true){
35947 var panelId = panel.getId();
35948 this.panels.removeKey(panelId);
35953 * Returns the panel specified or null if it's not in this region.
35954 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35955 * @return {Roo.ContentPanel}
35957 getPanel : function(id){
35958 if(typeof id == "object"){ // must be panel obj
35961 return this.panels.get(id);
35965 * Returns this regions position (north/south/east/west/center).
35968 getPosition: function(){
35969 return this.position;
35973 * Ext JS Library 1.1.1
35974 * Copyright(c) 2006-2007, Ext JS, LLC.
35976 * Originally Released Under LGPL - original licence link has changed is not relivant.
35979 * <script type="text/javascript">
35983 * @class Roo.bootstrap.layout.Region
35984 * @extends Roo.bootstrap.layout.Basic
35985 * This class represents a region in a layout manager.
35987 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35988 * @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})
35989 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35990 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35991 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35992 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35993 * @cfg {String} title The title for the region (overrides panel titles)
35994 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35995 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35996 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35997 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35998 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35999 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
36000 * the space available, similar to FireFox 1.5 tabs (defaults to false)
36001 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
36002 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
36003 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
36005 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
36006 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36007 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36008 * @cfg {Number} width For East/West panels
36009 * @cfg {Number} height For North/South panels
36010 * @cfg {Boolean} split To show the splitter
36011 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36013 * @cfg {string} cls Extra CSS classes to add to region
36015 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36016 * @cfg {string} region the region that it inhabits..
36019 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36020 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36022 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36023 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36024 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36026 Roo.bootstrap.layout.Region = function(config)
36028 this.applyConfig(config);
36030 var mgr = config.mgr;
36031 var pos = config.region;
36032 config.skipConfig = true;
36033 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36036 this.onRender(mgr.el);
36039 this.visible = true;
36040 this.collapsed = false;
36041 this.unrendered_panels = [];
36044 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36046 position: '', // set by wrapper (eg. north/south etc..)
36047 unrendered_panels : null, // unrendered panels.
36049 tabPosition : false,
36051 mgr: false, // points to 'Border'
36054 createBody : function(){
36055 /** This region's body element
36056 * @type Roo.Element */
36057 this.bodyEl = this.el.createChild({
36059 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36063 onRender: function(ctr, pos)
36065 var dh = Roo.DomHelper;
36066 /** This region's container element
36067 * @type Roo.Element */
36068 this.el = dh.append(ctr.dom, {
36070 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36072 /** This region's title element
36073 * @type Roo.Element */
36075 this.titleEl = dh.append(this.el.dom, {
36077 unselectable: "on",
36078 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36080 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36081 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36085 this.titleEl.enableDisplayMode();
36086 /** This region's title text element
36087 * @type HTMLElement */
36088 this.titleTextEl = this.titleEl.dom.firstChild;
36089 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36091 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36092 this.closeBtn.enableDisplayMode();
36093 this.closeBtn.on("click", this.closeClicked, this);
36094 this.closeBtn.hide();
36096 this.createBody(this.config);
36097 if(this.config.hideWhenEmpty){
36099 this.on("paneladded", this.validateVisibility, this);
36100 this.on("panelremoved", this.validateVisibility, this);
36102 if(this.autoScroll){
36103 this.bodyEl.setStyle("overflow", "auto");
36105 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36107 //if(c.titlebar !== false){
36108 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36109 this.titleEl.hide();
36111 this.titleEl.show();
36112 if(this.config.title){
36113 this.titleTextEl.innerHTML = this.config.title;
36117 if(this.config.collapsed){
36118 this.collapse(true);
36120 if(this.config.hidden){
36124 if (this.unrendered_panels && this.unrendered_panels.length) {
36125 for (var i =0;i< this.unrendered_panels.length; i++) {
36126 this.add(this.unrendered_panels[i]);
36128 this.unrendered_panels = null;
36134 applyConfig : function(c)
36137 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36138 var dh = Roo.DomHelper;
36139 if(c.titlebar !== false){
36140 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36141 this.collapseBtn.on("click", this.collapse, this);
36142 this.collapseBtn.enableDisplayMode();
36144 if(c.showPin === true || this.showPin){
36145 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36146 this.stickBtn.enableDisplayMode();
36147 this.stickBtn.on("click", this.expand, this);
36148 this.stickBtn.hide();
36153 /** This region's collapsed element
36154 * @type Roo.Element */
36157 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36158 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36161 if(c.floatable !== false){
36162 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36163 this.collapsedEl.on("click", this.collapseClick, this);
36166 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36167 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36168 id: "message", unselectable: "on", style:{"float":"left"}});
36169 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36171 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36172 this.expandBtn.on("click", this.expand, this);
36176 if(this.collapseBtn){
36177 this.collapseBtn.setVisible(c.collapsible == true);
36180 this.cmargins = c.cmargins || this.cmargins ||
36181 (this.position == "west" || this.position == "east" ?
36182 {top: 0, left: 2, right:2, bottom: 0} :
36183 {top: 2, left: 0, right:0, bottom: 2});
36185 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36188 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36190 this.autoScroll = c.autoScroll || false;
36195 this.duration = c.duration || .30;
36196 this.slideDuration = c.slideDuration || .45;
36201 * Returns true if this region is currently visible.
36202 * @return {Boolean}
36204 isVisible : function(){
36205 return this.visible;
36209 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36210 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36212 //setCollapsedTitle : function(title){
36213 // title = title || " ";
36214 // if(this.collapsedTitleTextEl){
36215 // this.collapsedTitleTextEl.innerHTML = title;
36219 getBox : function(){
36221 // if(!this.collapsed){
36222 b = this.el.getBox(false, true);
36224 // b = this.collapsedEl.getBox(false, true);
36229 getMargins : function(){
36230 return this.margins;
36231 //return this.collapsed ? this.cmargins : this.margins;
36234 highlight : function(){
36235 this.el.addClass("x-layout-panel-dragover");
36238 unhighlight : function(){
36239 this.el.removeClass("x-layout-panel-dragover");
36242 updateBox : function(box)
36244 if (!this.bodyEl) {
36245 return; // not rendered yet..
36249 if(!this.collapsed){
36250 this.el.dom.style.left = box.x + "px";
36251 this.el.dom.style.top = box.y + "px";
36252 this.updateBody(box.width, box.height);
36254 this.collapsedEl.dom.style.left = box.x + "px";
36255 this.collapsedEl.dom.style.top = box.y + "px";
36256 this.collapsedEl.setSize(box.width, box.height);
36259 this.tabs.autoSizeTabs();
36263 updateBody : function(w, h)
36266 this.el.setWidth(w);
36267 w -= this.el.getBorderWidth("rl");
36268 if(this.config.adjustments){
36269 w += this.config.adjustments[0];
36272 if(h !== null && h > 0){
36273 this.el.setHeight(h);
36274 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36275 h -= this.el.getBorderWidth("tb");
36276 if(this.config.adjustments){
36277 h += this.config.adjustments[1];
36279 this.bodyEl.setHeight(h);
36281 h = this.tabs.syncHeight(h);
36284 if(this.panelSize){
36285 w = w !== null ? w : this.panelSize.width;
36286 h = h !== null ? h : this.panelSize.height;
36288 if(this.activePanel){
36289 var el = this.activePanel.getEl();
36290 w = w !== null ? w : el.getWidth();
36291 h = h !== null ? h : el.getHeight();
36292 this.panelSize = {width: w, height: h};
36293 this.activePanel.setSize(w, h);
36295 if(Roo.isIE && this.tabs){
36296 this.tabs.el.repaint();
36301 * Returns the container element for this region.
36302 * @return {Roo.Element}
36304 getEl : function(){
36309 * Hides this region.
36312 //if(!this.collapsed){
36313 this.el.dom.style.left = "-2000px";
36316 // this.collapsedEl.dom.style.left = "-2000px";
36317 // this.collapsedEl.hide();
36319 this.visible = false;
36320 this.fireEvent("visibilitychange", this, false);
36324 * Shows this region if it was previously hidden.
36327 //if(!this.collapsed){
36330 // this.collapsedEl.show();
36332 this.visible = true;
36333 this.fireEvent("visibilitychange", this, true);
36336 closeClicked : function(){
36337 if(this.activePanel){
36338 this.remove(this.activePanel);
36342 collapseClick : function(e){
36344 e.stopPropagation();
36347 e.stopPropagation();
36353 * Collapses this region.
36354 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36357 collapse : function(skipAnim, skipCheck = false){
36358 if(this.collapsed) {
36362 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36364 this.collapsed = true;
36366 this.split.el.hide();
36368 if(this.config.animate && skipAnim !== true){
36369 this.fireEvent("invalidated", this);
36370 this.animateCollapse();
36372 this.el.setLocation(-20000,-20000);
36374 this.collapsedEl.show();
36375 this.fireEvent("collapsed", this);
36376 this.fireEvent("invalidated", this);
36382 animateCollapse : function(){
36387 * Expands this region if it was previously collapsed.
36388 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36389 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36392 expand : function(e, skipAnim){
36394 e.stopPropagation();
36396 if(!this.collapsed || this.el.hasActiveFx()) {
36400 this.afterSlideIn();
36403 this.collapsed = false;
36404 if(this.config.animate && skipAnim !== true){
36405 this.animateExpand();
36409 this.split.el.show();
36411 this.collapsedEl.setLocation(-2000,-2000);
36412 this.collapsedEl.hide();
36413 this.fireEvent("invalidated", this);
36414 this.fireEvent("expanded", this);
36418 animateExpand : function(){
36422 initTabs : function()
36424 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36426 var ts = new Roo.bootstrap.panel.Tabs({
36427 el: this.bodyEl.dom,
36429 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36430 disableTooltips: this.config.disableTabTips,
36431 toolbar : this.config.toolbar
36434 if(this.config.hideTabs){
36435 ts.stripWrap.setDisplayed(false);
36438 ts.resizeTabs = this.config.resizeTabs === true;
36439 ts.minTabWidth = this.config.minTabWidth || 40;
36440 ts.maxTabWidth = this.config.maxTabWidth || 250;
36441 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36442 ts.monitorResize = false;
36443 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36444 ts.bodyEl.addClass('roo-layout-tabs-body');
36445 this.panels.each(this.initPanelAsTab, this);
36448 initPanelAsTab : function(panel){
36449 var ti = this.tabs.addTab(
36453 this.config.closeOnTab && panel.isClosable(),
36456 if(panel.tabTip !== undefined){
36457 ti.setTooltip(panel.tabTip);
36459 ti.on("activate", function(){
36460 this.setActivePanel(panel);
36463 if(this.config.closeOnTab){
36464 ti.on("beforeclose", function(t, e){
36466 this.remove(panel);
36470 panel.tabItem = ti;
36475 updatePanelTitle : function(panel, title)
36477 if(this.activePanel == panel){
36478 this.updateTitle(title);
36481 var ti = this.tabs.getTab(panel.getEl().id);
36483 if(panel.tabTip !== undefined){
36484 ti.setTooltip(panel.tabTip);
36489 updateTitle : function(title){
36490 if(this.titleTextEl && !this.config.title){
36491 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36495 setActivePanel : function(panel)
36497 panel = this.getPanel(panel);
36498 if(this.activePanel && this.activePanel != panel){
36499 if(this.activePanel.setActiveState(false) === false){
36503 this.activePanel = panel;
36504 panel.setActiveState(true);
36505 if(this.panelSize){
36506 panel.setSize(this.panelSize.width, this.panelSize.height);
36509 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36511 this.updateTitle(panel.getTitle());
36513 this.fireEvent("invalidated", this);
36515 this.fireEvent("panelactivated", this, panel);
36519 * Shows the specified panel.
36520 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36521 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36523 showPanel : function(panel)
36525 panel = this.getPanel(panel);
36528 var tab = this.tabs.getTab(panel.getEl().id);
36529 if(tab.isHidden()){
36530 this.tabs.unhideTab(tab.id);
36534 this.setActivePanel(panel);
36541 * Get the active panel for this region.
36542 * @return {Roo.ContentPanel} The active panel or null
36544 getActivePanel : function(){
36545 return this.activePanel;
36548 validateVisibility : function(){
36549 if(this.panels.getCount() < 1){
36550 this.updateTitle(" ");
36551 this.closeBtn.hide();
36554 if(!this.isVisible()){
36561 * Adds the passed ContentPanel(s) to this region.
36562 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36563 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36565 add : function(panel)
36567 if(arguments.length > 1){
36568 for(var i = 0, len = arguments.length; i < len; i++) {
36569 this.add(arguments[i]);
36574 // if we have not been rendered yet, then we can not really do much of this..
36575 if (!this.bodyEl) {
36576 this.unrendered_panels.push(panel);
36583 if(this.hasPanel(panel)){
36584 this.showPanel(panel);
36587 panel.setRegion(this);
36588 this.panels.add(panel);
36589 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36590 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36591 // and hide them... ???
36592 this.bodyEl.dom.appendChild(panel.getEl().dom);
36593 if(panel.background !== true){
36594 this.setActivePanel(panel);
36596 this.fireEvent("paneladded", this, panel);
36603 this.initPanelAsTab(panel);
36607 if(panel.background !== true){
36608 this.tabs.activate(panel.getEl().id);
36610 this.fireEvent("paneladded", this, panel);
36615 * Hides the tab for the specified panel.
36616 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36618 hidePanel : function(panel){
36619 if(this.tabs && (panel = this.getPanel(panel))){
36620 this.tabs.hideTab(panel.getEl().id);
36625 * Unhides the tab for a previously hidden panel.
36626 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36628 unhidePanel : function(panel){
36629 if(this.tabs && (panel = this.getPanel(panel))){
36630 this.tabs.unhideTab(panel.getEl().id);
36634 clearPanels : function(){
36635 while(this.panels.getCount() > 0){
36636 this.remove(this.panels.first());
36641 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36642 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36643 * @param {Boolean} preservePanel Overrides the config preservePanel option
36644 * @return {Roo.ContentPanel} The panel that was removed
36646 remove : function(panel, preservePanel)
36648 panel = this.getPanel(panel);
36653 this.fireEvent("beforeremove", this, panel, e);
36654 if(e.cancel === true){
36657 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36658 var panelId = panel.getId();
36659 this.panels.removeKey(panelId);
36661 document.body.appendChild(panel.getEl().dom);
36664 this.tabs.removeTab(panel.getEl().id);
36665 }else if (!preservePanel){
36666 this.bodyEl.dom.removeChild(panel.getEl().dom);
36668 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36669 var p = this.panels.first();
36670 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36671 tempEl.appendChild(p.getEl().dom);
36672 this.bodyEl.update("");
36673 this.bodyEl.dom.appendChild(p.getEl().dom);
36675 this.updateTitle(p.getTitle());
36677 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36678 this.setActivePanel(p);
36680 panel.setRegion(null);
36681 if(this.activePanel == panel){
36682 this.activePanel = null;
36684 if(this.config.autoDestroy !== false && preservePanel !== true){
36685 try{panel.destroy();}catch(e){}
36687 this.fireEvent("panelremoved", this, panel);
36692 * Returns the TabPanel component used by this region
36693 * @return {Roo.TabPanel}
36695 getTabs : function(){
36699 createTool : function(parentEl, className){
36700 var btn = Roo.DomHelper.append(parentEl, {
36702 cls: "x-layout-tools-button",
36705 cls: "roo-layout-tools-button-inner " + className,
36709 btn.addClassOnOver("roo-layout-tools-button-over");
36714 * Ext JS Library 1.1.1
36715 * Copyright(c) 2006-2007, Ext JS, LLC.
36717 * Originally Released Under LGPL - original licence link has changed is not relivant.
36720 * <script type="text/javascript">
36726 * @class Roo.SplitLayoutRegion
36727 * @extends Roo.LayoutRegion
36728 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36730 Roo.bootstrap.layout.Split = function(config){
36731 this.cursor = config.cursor;
36732 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36735 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36737 splitTip : "Drag to resize.",
36738 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36739 useSplitTips : false,
36741 applyConfig : function(config){
36742 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36745 onRender : function(ctr,pos) {
36747 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36748 if(!this.config.split){
36753 var splitEl = Roo.DomHelper.append(ctr.dom, {
36755 id: this.el.id + "-split",
36756 cls: "roo-layout-split roo-layout-split-"+this.position,
36759 /** The SplitBar for this region
36760 * @type Roo.SplitBar */
36761 // does not exist yet...
36762 Roo.log([this.position, this.orientation]);
36764 this.split = new Roo.bootstrap.SplitBar({
36765 dragElement : splitEl,
36766 resizingElement: this.el,
36767 orientation : this.orientation
36770 this.split.on("moved", this.onSplitMove, this);
36771 this.split.useShim = this.config.useShim === true;
36772 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36773 if(this.useSplitTips){
36774 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36776 //if(config.collapsible){
36777 // this.split.el.on("dblclick", this.collapse, this);
36780 if(typeof this.config.minSize != "undefined"){
36781 this.split.minSize = this.config.minSize;
36783 if(typeof this.config.maxSize != "undefined"){
36784 this.split.maxSize = this.config.maxSize;
36786 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36787 this.hideSplitter();
36792 getHMaxSize : function(){
36793 var cmax = this.config.maxSize || 10000;
36794 var center = this.mgr.getRegion("center");
36795 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36798 getVMaxSize : function(){
36799 var cmax = this.config.maxSize || 10000;
36800 var center = this.mgr.getRegion("center");
36801 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36804 onSplitMove : function(split, newSize){
36805 this.fireEvent("resized", this, newSize);
36809 * Returns the {@link Roo.SplitBar} for this region.
36810 * @return {Roo.SplitBar}
36812 getSplitBar : function(){
36817 this.hideSplitter();
36818 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36821 hideSplitter : function(){
36823 this.split.el.setLocation(-2000,-2000);
36824 this.split.el.hide();
36830 this.split.el.show();
36832 Roo.bootstrap.layout.Split.superclass.show.call(this);
36835 beforeSlide: function(){
36836 if(Roo.isGecko){// firefox overflow auto bug workaround
36837 this.bodyEl.clip();
36839 this.tabs.bodyEl.clip();
36841 if(this.activePanel){
36842 this.activePanel.getEl().clip();
36844 if(this.activePanel.beforeSlide){
36845 this.activePanel.beforeSlide();
36851 afterSlide : function(){
36852 if(Roo.isGecko){// firefox overflow auto bug workaround
36853 this.bodyEl.unclip();
36855 this.tabs.bodyEl.unclip();
36857 if(this.activePanel){
36858 this.activePanel.getEl().unclip();
36859 if(this.activePanel.afterSlide){
36860 this.activePanel.afterSlide();
36866 initAutoHide : function(){
36867 if(this.autoHide !== false){
36868 if(!this.autoHideHd){
36869 var st = new Roo.util.DelayedTask(this.slideIn, this);
36870 this.autoHideHd = {
36871 "mouseout": function(e){
36872 if(!e.within(this.el, true)){
36876 "mouseover" : function(e){
36882 this.el.on(this.autoHideHd);
36886 clearAutoHide : function(){
36887 if(this.autoHide !== false){
36888 this.el.un("mouseout", this.autoHideHd.mouseout);
36889 this.el.un("mouseover", this.autoHideHd.mouseover);
36893 clearMonitor : function(){
36894 Roo.get(document).un("click", this.slideInIf, this);
36897 // these names are backwards but not changed for compat
36898 slideOut : function(){
36899 if(this.isSlid || this.el.hasActiveFx()){
36902 this.isSlid = true;
36903 if(this.collapseBtn){
36904 this.collapseBtn.hide();
36906 this.closeBtnState = this.closeBtn.getStyle('display');
36907 this.closeBtn.hide();
36909 this.stickBtn.show();
36912 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36913 this.beforeSlide();
36914 this.el.setStyle("z-index", 10001);
36915 this.el.slideIn(this.getSlideAnchor(), {
36916 callback: function(){
36918 this.initAutoHide();
36919 Roo.get(document).on("click", this.slideInIf, this);
36920 this.fireEvent("slideshow", this);
36927 afterSlideIn : function(){
36928 this.clearAutoHide();
36929 this.isSlid = false;
36930 this.clearMonitor();
36931 this.el.setStyle("z-index", "");
36932 if(this.collapseBtn){
36933 this.collapseBtn.show();
36935 this.closeBtn.setStyle('display', this.closeBtnState);
36937 this.stickBtn.hide();
36939 this.fireEvent("slidehide", this);
36942 slideIn : function(cb){
36943 if(!this.isSlid || this.el.hasActiveFx()){
36947 this.isSlid = false;
36948 this.beforeSlide();
36949 this.el.slideOut(this.getSlideAnchor(), {
36950 callback: function(){
36951 this.el.setLeftTop(-10000, -10000);
36953 this.afterSlideIn();
36961 slideInIf : function(e){
36962 if(!e.within(this.el)){
36967 animateCollapse : function(){
36968 this.beforeSlide();
36969 this.el.setStyle("z-index", 20000);
36970 var anchor = this.getSlideAnchor();
36971 this.el.slideOut(anchor, {
36972 callback : function(){
36973 this.el.setStyle("z-index", "");
36974 this.collapsedEl.slideIn(anchor, {duration:.3});
36976 this.el.setLocation(-10000,-10000);
36978 this.fireEvent("collapsed", this);
36985 animateExpand : function(){
36986 this.beforeSlide();
36987 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36988 this.el.setStyle("z-index", 20000);
36989 this.collapsedEl.hide({
36992 this.el.slideIn(this.getSlideAnchor(), {
36993 callback : function(){
36994 this.el.setStyle("z-index", "");
36997 this.split.el.show();
36999 this.fireEvent("invalidated", this);
37000 this.fireEvent("expanded", this);
37028 getAnchor : function(){
37029 return this.anchors[this.position];
37032 getCollapseAnchor : function(){
37033 return this.canchors[this.position];
37036 getSlideAnchor : function(){
37037 return this.sanchors[this.position];
37040 getAlignAdj : function(){
37041 var cm = this.cmargins;
37042 switch(this.position){
37058 getExpandAdj : function(){
37059 var c = this.collapsedEl, cm = this.cmargins;
37060 switch(this.position){
37062 return [-(cm.right+c.getWidth()+cm.left), 0];
37065 return [cm.right+c.getWidth()+cm.left, 0];
37068 return [0, -(cm.top+cm.bottom+c.getHeight())];
37071 return [0, cm.top+cm.bottom+c.getHeight()];
37077 * Ext JS Library 1.1.1
37078 * Copyright(c) 2006-2007, Ext JS, LLC.
37080 * Originally Released Under LGPL - original licence link has changed is not relivant.
37083 * <script type="text/javascript">
37086 * These classes are private internal classes
37088 Roo.bootstrap.layout.Center = function(config){
37089 config.region = "center";
37090 Roo.bootstrap.layout.Region.call(this, config);
37091 this.visible = true;
37092 this.minWidth = config.minWidth || 20;
37093 this.minHeight = config.minHeight || 20;
37096 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37098 // center panel can't be hidden
37102 // center panel can't be hidden
37105 getMinWidth: function(){
37106 return this.minWidth;
37109 getMinHeight: function(){
37110 return this.minHeight;
37124 Roo.bootstrap.layout.North = function(config)
37126 config.region = 'north';
37127 config.cursor = 'n-resize';
37129 Roo.bootstrap.layout.Split.call(this, config);
37133 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37134 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37135 this.split.el.addClass("roo-layout-split-v");
37137 var size = config.initialSize || config.height;
37138 if(typeof size != "undefined"){
37139 this.el.setHeight(size);
37142 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37144 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37148 getBox : function(){
37149 if(this.collapsed){
37150 return this.collapsedEl.getBox();
37152 var box = this.el.getBox();
37154 box.height += this.split.el.getHeight();
37159 updateBox : function(box){
37160 if(this.split && !this.collapsed){
37161 box.height -= this.split.el.getHeight();
37162 this.split.el.setLeft(box.x);
37163 this.split.el.setTop(box.y+box.height);
37164 this.split.el.setWidth(box.width);
37166 if(this.collapsed){
37167 this.updateBody(box.width, null);
37169 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37177 Roo.bootstrap.layout.South = function(config){
37178 config.region = 'south';
37179 config.cursor = 's-resize';
37180 Roo.bootstrap.layout.Split.call(this, config);
37182 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37183 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37184 this.split.el.addClass("roo-layout-split-v");
37186 var size = config.initialSize || config.height;
37187 if(typeof size != "undefined"){
37188 this.el.setHeight(size);
37192 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37193 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37194 getBox : function(){
37195 if(this.collapsed){
37196 return this.collapsedEl.getBox();
37198 var box = this.el.getBox();
37200 var sh = this.split.el.getHeight();
37207 updateBox : function(box){
37208 if(this.split && !this.collapsed){
37209 var sh = this.split.el.getHeight();
37212 this.split.el.setLeft(box.x);
37213 this.split.el.setTop(box.y-sh);
37214 this.split.el.setWidth(box.width);
37216 if(this.collapsed){
37217 this.updateBody(box.width, null);
37219 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37223 Roo.bootstrap.layout.East = function(config){
37224 config.region = "east";
37225 config.cursor = "e-resize";
37226 Roo.bootstrap.layout.Split.call(this, config);
37228 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37229 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37230 this.split.el.addClass("roo-layout-split-h");
37232 var size = config.initialSize || config.width;
37233 if(typeof size != "undefined"){
37234 this.el.setWidth(size);
37237 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37238 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37239 getBox : function(){
37240 if(this.collapsed){
37241 return this.collapsedEl.getBox();
37243 var box = this.el.getBox();
37245 var sw = this.split.el.getWidth();
37252 updateBox : function(box){
37253 if(this.split && !this.collapsed){
37254 var sw = this.split.el.getWidth();
37256 this.split.el.setLeft(box.x);
37257 this.split.el.setTop(box.y);
37258 this.split.el.setHeight(box.height);
37261 if(this.collapsed){
37262 this.updateBody(null, box.height);
37264 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37268 Roo.bootstrap.layout.West = function(config){
37269 config.region = "west";
37270 config.cursor = "w-resize";
37272 Roo.bootstrap.layout.Split.call(this, config);
37274 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37275 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37276 this.split.el.addClass("roo-layout-split-h");
37280 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37281 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37283 onRender: function(ctr, pos)
37285 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37286 var size = this.config.initialSize || this.config.width;
37287 if(typeof size != "undefined"){
37288 this.el.setWidth(size);
37292 getBox : function(){
37293 if(this.collapsed){
37294 return this.collapsedEl.getBox();
37296 var box = this.el.getBox();
37298 box.width += this.split.el.getWidth();
37303 updateBox : function(box){
37304 if(this.split && !this.collapsed){
37305 var sw = this.split.el.getWidth();
37307 this.split.el.setLeft(box.x+box.width);
37308 this.split.el.setTop(box.y);
37309 this.split.el.setHeight(box.height);
37311 if(this.collapsed){
37312 this.updateBody(null, box.height);
37314 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37316 });Roo.namespace("Roo.bootstrap.panel");/*
37318 * Ext JS Library 1.1.1
37319 * Copyright(c) 2006-2007, Ext JS, LLC.
37321 * Originally Released Under LGPL - original licence link has changed is not relivant.
37324 * <script type="text/javascript">
37327 * @class Roo.ContentPanel
37328 * @extends Roo.util.Observable
37329 * A basic ContentPanel element.
37330 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37331 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37332 * @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
37333 * @cfg {Boolean} closable True if the panel can be closed/removed
37334 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37335 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37336 * @cfg {Toolbar} toolbar A toolbar for this panel
37337 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37338 * @cfg {String} title The title for this panel
37339 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37340 * @cfg {String} url Calls {@link #setUrl} with this value
37341 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37342 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37343 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37344 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37345 * @cfg {Boolean} badges render the badges
37348 * Create a new ContentPanel.
37349 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37350 * @param {String/Object} config A string to set only the title or a config object
37351 * @param {String} content (optional) Set the HTML content for this panel
37352 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37354 Roo.bootstrap.panel.Content = function( config){
37356 this.tpl = config.tpl || false;
37358 var el = config.el;
37359 var content = config.content;
37361 if(config.autoCreate){ // xtype is available if this is called from factory
37364 this.el = Roo.get(el);
37365 if(!this.el && config && config.autoCreate){
37366 if(typeof config.autoCreate == "object"){
37367 if(!config.autoCreate.id){
37368 config.autoCreate.id = config.id||el;
37370 this.el = Roo.DomHelper.append(document.body,
37371 config.autoCreate, true);
37373 var elcfg = { tag: "div",
37374 cls: "roo-layout-inactive-content",
37378 elcfg.html = config.html;
37382 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37385 this.closable = false;
37386 this.loaded = false;
37387 this.active = false;
37390 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37392 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37394 this.wrapEl = this.el; //this.el.wrap();
37396 if (config.toolbar.items) {
37397 ti = config.toolbar.items ;
37398 delete config.toolbar.items ;
37402 this.toolbar.render(this.wrapEl, 'before');
37403 for(var i =0;i < ti.length;i++) {
37404 // Roo.log(['add child', items[i]]);
37405 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37407 this.toolbar.items = nitems;
37408 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37409 delete config.toolbar;
37413 // xtype created footer. - not sure if will work as we normally have to render first..
37414 if (this.footer && !this.footer.el && this.footer.xtype) {
37415 if (!this.wrapEl) {
37416 this.wrapEl = this.el.wrap();
37419 this.footer.container = this.wrapEl.createChild();
37421 this.footer = Roo.factory(this.footer, Roo);
37426 if(typeof config == "string"){
37427 this.title = config;
37429 Roo.apply(this, config);
37433 this.resizeEl = Roo.get(this.resizeEl, true);
37435 this.resizeEl = this.el;
37437 // handle view.xtype
37445 * Fires when this panel is activated.
37446 * @param {Roo.ContentPanel} this
37450 * @event deactivate
37451 * Fires when this panel is activated.
37452 * @param {Roo.ContentPanel} this
37454 "deactivate" : true,
37458 * Fires when this panel is resized if fitToFrame is true.
37459 * @param {Roo.ContentPanel} this
37460 * @param {Number} width The width after any component adjustments
37461 * @param {Number} height The height after any component adjustments
37467 * Fires when this tab is created
37468 * @param {Roo.ContentPanel} this
37479 if(this.autoScroll){
37480 this.resizeEl.setStyle("overflow", "auto");
37482 // fix randome scrolling
37483 //this.el.on('scroll', function() {
37484 // Roo.log('fix random scolling');
37485 // this.scrollTo('top',0);
37488 content = content || this.content;
37490 this.setContent(content);
37492 if(config && config.url){
37493 this.setUrl(this.url, this.params, this.loadOnce);
37498 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37500 if (this.view && typeof(this.view.xtype) != 'undefined') {
37501 this.view.el = this.el.appendChild(document.createElement("div"));
37502 this.view = Roo.factory(this.view);
37503 this.view.render && this.view.render(false, '');
37507 this.fireEvent('render', this);
37510 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37514 setRegion : function(region){
37515 this.region = region;
37516 this.setActiveClass(region && !this.background);
37520 setActiveClass: function(state)
37523 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37524 this.el.setStyle('position','relative');
37526 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37527 this.el.setStyle('position', 'absolute');
37532 * Returns the toolbar for this Panel if one was configured.
37533 * @return {Roo.Toolbar}
37535 getToolbar : function(){
37536 return this.toolbar;
37539 setActiveState : function(active)
37541 this.active = active;
37542 this.setActiveClass(active);
37544 if(this.fireEvent("deactivate", this) === false){
37549 this.fireEvent("activate", this);
37553 * Updates this panel's element
37554 * @param {String} content The new content
37555 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37557 setContent : function(content, loadScripts){
37558 this.el.update(content, loadScripts);
37561 ignoreResize : function(w, h){
37562 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37565 this.lastSize = {width: w, height: h};
37570 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37571 * @return {Roo.UpdateManager} The UpdateManager
37573 getUpdateManager : function(){
37574 return this.el.getUpdateManager();
37577 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37578 * @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:
37581 url: "your-url.php",
37582 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37583 callback: yourFunction,
37584 scope: yourObject, //(optional scope)
37587 text: "Loading...",
37592 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37593 * 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.
37594 * @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}
37595 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37596 * @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.
37597 * @return {Roo.ContentPanel} this
37600 var um = this.el.getUpdateManager();
37601 um.update.apply(um, arguments);
37607 * 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.
37608 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37609 * @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)
37610 * @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)
37611 * @return {Roo.UpdateManager} The UpdateManager
37613 setUrl : function(url, params, loadOnce){
37614 if(this.refreshDelegate){
37615 this.removeListener("activate", this.refreshDelegate);
37617 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37618 this.on("activate", this.refreshDelegate);
37619 return this.el.getUpdateManager();
37622 _handleRefresh : function(url, params, loadOnce){
37623 if(!loadOnce || !this.loaded){
37624 var updater = this.el.getUpdateManager();
37625 updater.update(url, params, this._setLoaded.createDelegate(this));
37629 _setLoaded : function(){
37630 this.loaded = true;
37634 * Returns this panel's id
37637 getId : function(){
37642 * Returns this panel's element - used by regiosn to add.
37643 * @return {Roo.Element}
37645 getEl : function(){
37646 return this.wrapEl || this.el;
37651 adjustForComponents : function(width, height)
37653 //Roo.log('adjustForComponents ');
37654 if(this.resizeEl != this.el){
37655 width -= this.el.getFrameWidth('lr');
37656 height -= this.el.getFrameWidth('tb');
37659 var te = this.toolbar.getEl();
37660 te.setWidth(width);
37661 height -= te.getHeight();
37664 var te = this.footer.getEl();
37665 te.setWidth(width);
37666 height -= te.getHeight();
37670 if(this.adjustments){
37671 width += this.adjustments[0];
37672 height += this.adjustments[1];
37674 return {"width": width, "height": height};
37677 setSize : function(width, height){
37678 if(this.fitToFrame && !this.ignoreResize(width, height)){
37679 if(this.fitContainer && this.resizeEl != this.el){
37680 this.el.setSize(width, height);
37682 var size = this.adjustForComponents(width, height);
37683 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37684 this.fireEvent('resize', this, size.width, size.height);
37689 * Returns this panel's title
37692 getTitle : function(){
37694 if (typeof(this.title) != 'object') {
37699 for (var k in this.title) {
37700 if (!this.title.hasOwnProperty(k)) {
37704 if (k.indexOf('-') >= 0) {
37705 var s = k.split('-');
37706 for (var i = 0; i<s.length; i++) {
37707 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37710 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37717 * Set this panel's title
37718 * @param {String} title
37720 setTitle : function(title){
37721 this.title = title;
37723 this.region.updatePanelTitle(this, title);
37728 * Returns true is this panel was configured to be closable
37729 * @return {Boolean}
37731 isClosable : function(){
37732 return this.closable;
37735 beforeSlide : function(){
37737 this.resizeEl.clip();
37740 afterSlide : function(){
37742 this.resizeEl.unclip();
37746 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37747 * Will fail silently if the {@link #setUrl} method has not been called.
37748 * This does not activate the panel, just updates its content.
37750 refresh : function(){
37751 if(this.refreshDelegate){
37752 this.loaded = false;
37753 this.refreshDelegate();
37758 * Destroys this panel
37760 destroy : function(){
37761 this.el.removeAllListeners();
37762 var tempEl = document.createElement("span");
37763 tempEl.appendChild(this.el.dom);
37764 tempEl.innerHTML = "";
37770 * form - if the content panel contains a form - this is a reference to it.
37771 * @type {Roo.form.Form}
37775 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37776 * This contains a reference to it.
37782 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37792 * @param {Object} cfg Xtype definition of item to add.
37796 getChildContainer: function () {
37797 return this.getEl();
37802 var ret = new Roo.factory(cfg);
37807 if (cfg.xtype.match(/^Form$/)) {
37810 //if (this.footer) {
37811 // el = this.footer.container.insertSibling(false, 'before');
37813 el = this.el.createChild();
37816 this.form = new Roo.form.Form(cfg);
37819 if ( this.form.allItems.length) {
37820 this.form.render(el.dom);
37824 // should only have one of theses..
37825 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37826 // views.. should not be just added - used named prop 'view''
37828 cfg.el = this.el.appendChild(document.createElement("div"));
37831 var ret = new Roo.factory(cfg);
37833 ret.render && ret.render(false, ''); // render blank..
37843 * @class Roo.bootstrap.panel.Grid
37844 * @extends Roo.bootstrap.panel.Content
37846 * Create a new GridPanel.
37847 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37848 * @param {Object} config A the config object
37854 Roo.bootstrap.panel.Grid = function(config)
37858 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37859 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37861 config.el = this.wrapper;
37862 //this.el = this.wrapper;
37864 if (config.container) {
37865 // ctor'ed from a Border/panel.grid
37868 this.wrapper.setStyle("overflow", "hidden");
37869 this.wrapper.addClass('roo-grid-container');
37874 if(config.toolbar){
37875 var tool_el = this.wrapper.createChild();
37876 this.toolbar = Roo.factory(config.toolbar);
37878 if (config.toolbar.items) {
37879 ti = config.toolbar.items ;
37880 delete config.toolbar.items ;
37884 this.toolbar.render(tool_el);
37885 for(var i =0;i < ti.length;i++) {
37886 // Roo.log(['add child', items[i]]);
37887 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37889 this.toolbar.items = nitems;
37891 delete config.toolbar;
37894 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37895 config.grid.scrollBody = true;;
37896 config.grid.monitorWindowResize = false; // turn off autosizing
37897 config.grid.autoHeight = false;
37898 config.grid.autoWidth = false;
37900 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37902 if (config.background) {
37903 // render grid on panel activation (if panel background)
37904 this.on('activate', function(gp) {
37905 if (!gp.grid.rendered) {
37906 gp.grid.render(this.wrapper);
37907 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37912 this.grid.render(this.wrapper);
37913 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37916 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37917 // ??? needed ??? config.el = this.wrapper;
37922 // xtype created footer. - not sure if will work as we normally have to render first..
37923 if (this.footer && !this.footer.el && this.footer.xtype) {
37925 var ctr = this.grid.getView().getFooterPanel(true);
37926 this.footer.dataSource = this.grid.dataSource;
37927 this.footer = Roo.factory(this.footer, Roo);
37928 this.footer.render(ctr);
37938 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37939 getId : function(){
37940 return this.grid.id;
37944 * Returns the grid for this panel
37945 * @return {Roo.bootstrap.Table}
37947 getGrid : function(){
37951 setSize : function(width, height){
37952 if(!this.ignoreResize(width, height)){
37953 var grid = this.grid;
37954 var size = this.adjustForComponents(width, height);
37955 var gridel = grid.getGridEl();
37956 gridel.setSize(size.width, size.height);
37958 var thd = grid.getGridEl().select('thead',true).first();
37959 var tbd = grid.getGridEl().select('tbody', true).first();
37961 tbd.setSize(width, height - thd.getHeight());
37970 beforeSlide : function(){
37971 this.grid.getView().scroller.clip();
37974 afterSlide : function(){
37975 this.grid.getView().scroller.unclip();
37978 destroy : function(){
37979 this.grid.destroy();
37981 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37986 * @class Roo.bootstrap.panel.Nest
37987 * @extends Roo.bootstrap.panel.Content
37989 * Create a new Panel, that can contain a layout.Border.
37992 * @param {Roo.BorderLayout} layout The layout for this panel
37993 * @param {String/Object} config A string to set only the title or a config object
37995 Roo.bootstrap.panel.Nest = function(config)
37997 // construct with only one argument..
37998 /* FIXME - implement nicer consturctors
37999 if (layout.layout) {
38001 layout = config.layout;
38002 delete config.layout;
38004 if (layout.xtype && !layout.getEl) {
38005 // then layout needs constructing..
38006 layout = Roo.factory(layout, Roo);
38010 config.el = config.layout.getEl();
38012 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38014 config.layout.monitorWindowResize = false; // turn off autosizing
38015 this.layout = config.layout;
38016 this.layout.getEl().addClass("roo-layout-nested-layout");
38017 this.layout.parent = this;
38024 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38026 setSize : function(width, height){
38027 if(!this.ignoreResize(width, height)){
38028 var size = this.adjustForComponents(width, height);
38029 var el = this.layout.getEl();
38030 if (size.height < 1) {
38031 el.setWidth(size.width);
38033 el.setSize(size.width, size.height);
38035 var touch = el.dom.offsetWidth;
38036 this.layout.layout();
38037 // ie requires a double layout on the first pass
38038 if(Roo.isIE && !this.initialized){
38039 this.initialized = true;
38040 this.layout.layout();
38045 // activate all subpanels if not currently active..
38047 setActiveState : function(active){
38048 this.active = active;
38049 this.setActiveClass(active);
38052 this.fireEvent("deactivate", this);
38056 this.fireEvent("activate", this);
38057 // not sure if this should happen before or after..
38058 if (!this.layout) {
38059 return; // should not happen..
38062 for (var r in this.layout.regions) {
38063 reg = this.layout.getRegion(r);
38064 if (reg.getActivePanel()) {
38065 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38066 reg.setActivePanel(reg.getActivePanel());
38069 if (!reg.panels.length) {
38072 reg.showPanel(reg.getPanel(0));
38081 * Returns the nested BorderLayout for this panel
38082 * @return {Roo.BorderLayout}
38084 getLayout : function(){
38085 return this.layout;
38089 * Adds a xtype elements to the layout of the nested panel
38093 xtype : 'ContentPanel',
38100 xtype : 'NestedLayoutPanel',
38106 items : [ ... list of content panels or nested layout panels.. ]
38110 * @param {Object} cfg Xtype definition of item to add.
38112 addxtype : function(cfg) {
38113 return this.layout.addxtype(cfg);
38118 * Ext JS Library 1.1.1
38119 * Copyright(c) 2006-2007, Ext JS, LLC.
38121 * Originally Released Under LGPL - original licence link has changed is not relivant.
38124 * <script type="text/javascript">
38127 * @class Roo.TabPanel
38128 * @extends Roo.util.Observable
38129 * A lightweight tab container.
38133 // basic tabs 1, built from existing content
38134 var tabs = new Roo.TabPanel("tabs1");
38135 tabs.addTab("script", "View Script");
38136 tabs.addTab("markup", "View Markup");
38137 tabs.activate("script");
38139 // more advanced tabs, built from javascript
38140 var jtabs = new Roo.TabPanel("jtabs");
38141 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38143 // set up the UpdateManager
38144 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38145 var updater = tab2.getUpdateManager();
38146 updater.setDefaultUrl("ajax1.htm");
38147 tab2.on('activate', updater.refresh, updater, true);
38149 // Use setUrl for Ajax loading
38150 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38151 tab3.setUrl("ajax2.htm", null, true);
38154 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38157 jtabs.activate("jtabs-1");
38160 * Create a new TabPanel.
38161 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38162 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38164 Roo.bootstrap.panel.Tabs = function(config){
38166 * The container element for this TabPanel.
38167 * @type Roo.Element
38169 this.el = Roo.get(config.el);
38172 if(typeof config == "boolean"){
38173 this.tabPosition = config ? "bottom" : "top";
38175 Roo.apply(this, config);
38179 if(this.tabPosition == "bottom"){
38180 // if tabs are at the bottom = create the body first.
38181 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38182 this.el.addClass("roo-tabs-bottom");
38184 // next create the tabs holders
38186 if (this.tabPosition == "west"){
38188 var reg = this.region; // fake it..
38190 if (!reg.mgr.parent) {
38193 reg = reg.mgr.parent.region;
38195 Roo.log("got nest?");
38197 if (reg.mgr.getRegion('west')) {
38198 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38199 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38200 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38201 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38202 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38210 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38211 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38212 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38213 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38218 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38221 // finally - if tabs are at the top, then create the body last..
38222 if(this.tabPosition != "bottom"){
38223 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38224 * @type Roo.Element
38226 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38227 this.el.addClass("roo-tabs-top");
38231 this.bodyEl.setStyle("position", "relative");
38233 this.active = null;
38234 this.activateDelegate = this.activate.createDelegate(this);
38239 * Fires when the active tab changes
38240 * @param {Roo.TabPanel} this
38241 * @param {Roo.TabPanelItem} activePanel The new active tab
38245 * @event beforetabchange
38246 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38247 * @param {Roo.TabPanel} this
38248 * @param {Object} e Set cancel to true on this object to cancel the tab change
38249 * @param {Roo.TabPanelItem} tab The tab being changed to
38251 "beforetabchange" : true
38254 Roo.EventManager.onWindowResize(this.onResize, this);
38255 this.cpad = this.el.getPadding("lr");
38256 this.hiddenCount = 0;
38259 // toolbar on the tabbar support...
38260 if (this.toolbar) {
38261 alert("no toolbar support yet");
38262 this.toolbar = false;
38264 var tcfg = this.toolbar;
38265 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38266 this.toolbar = new Roo.Toolbar(tcfg);
38267 if (Roo.isSafari) {
38268 var tbl = tcfg.container.child('table', true);
38269 tbl.setAttribute('width', '100%');
38277 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38280 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38282 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38284 tabPosition : "top",
38286 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38288 currentTabWidth : 0,
38290 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38294 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38298 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38300 preferredTabWidth : 175,
38302 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38304 resizeTabs : false,
38306 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38308 monitorResize : true,
38310 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38312 toolbar : false, // set by caller..
38314 region : false, /// set by caller
38316 disableTooltips : true, // not used yet...
38319 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38320 * @param {String} id The id of the div to use <b>or create</b>
38321 * @param {String} text The text for the tab
38322 * @param {String} content (optional) Content to put in the TabPanelItem body
38323 * @param {Boolean} closable (optional) True to create a close icon on the tab
38324 * @return {Roo.TabPanelItem} The created TabPanelItem
38326 addTab : function(id, text, content, closable, tpl)
38328 var item = new Roo.bootstrap.panel.TabItem({
38332 closable : closable,
38335 this.addTabItem(item);
38337 item.setContent(content);
38343 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38344 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38345 * @return {Roo.TabPanelItem}
38347 getTab : function(id){
38348 return this.items[id];
38352 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38353 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38355 hideTab : function(id){
38356 var t = this.items[id];
38359 this.hiddenCount++;
38360 this.autoSizeTabs();
38365 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38366 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38368 unhideTab : function(id){
38369 var t = this.items[id];
38371 t.setHidden(false);
38372 this.hiddenCount--;
38373 this.autoSizeTabs();
38378 * Adds an existing {@link Roo.TabPanelItem}.
38379 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38381 addTabItem : function(item)
38383 this.items[item.id] = item;
38384 this.items.push(item);
38385 this.autoSizeTabs();
38386 // if(this.resizeTabs){
38387 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38388 // this.autoSizeTabs();
38390 // item.autoSize();
38395 * Removes a {@link Roo.TabPanelItem}.
38396 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38398 removeTab : function(id){
38399 var items = this.items;
38400 var tab = items[id];
38401 if(!tab) { return; }
38402 var index = items.indexOf(tab);
38403 if(this.active == tab && items.length > 1){
38404 var newTab = this.getNextAvailable(index);
38409 this.stripEl.dom.removeChild(tab.pnode.dom);
38410 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38411 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38413 items.splice(index, 1);
38414 delete this.items[tab.id];
38415 tab.fireEvent("close", tab);
38416 tab.purgeListeners();
38417 this.autoSizeTabs();
38420 getNextAvailable : function(start){
38421 var items = this.items;
38423 // look for a next tab that will slide over to
38424 // replace the one being removed
38425 while(index < items.length){
38426 var item = items[++index];
38427 if(item && !item.isHidden()){
38431 // if one isn't found select the previous tab (on the left)
38434 var item = items[--index];
38435 if(item && !item.isHidden()){
38443 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38444 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38446 disableTab : function(id){
38447 var tab = this.items[id];
38448 if(tab && this.active != tab){
38454 * Enables a {@link Roo.TabPanelItem} that is disabled.
38455 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38457 enableTab : function(id){
38458 var tab = this.items[id];
38463 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38464 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38465 * @return {Roo.TabPanelItem} The TabPanelItem.
38467 activate : function(id)
38469 //Roo.log('activite:' + id);
38471 var tab = this.items[id];
38475 if(tab == this.active || tab.disabled){
38479 this.fireEvent("beforetabchange", this, e, tab);
38480 if(e.cancel !== true && !tab.disabled){
38482 this.active.hide();
38484 this.active = this.items[id];
38485 this.active.show();
38486 this.fireEvent("tabchange", this, this.active);
38492 * Gets the active {@link Roo.TabPanelItem}.
38493 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38495 getActiveTab : function(){
38496 return this.active;
38500 * Updates the tab body element to fit the height of the container element
38501 * for overflow scrolling
38502 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38504 syncHeight : function(targetHeight){
38505 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38506 var bm = this.bodyEl.getMargins();
38507 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38508 this.bodyEl.setHeight(newHeight);
38512 onResize : function(){
38513 if(this.monitorResize){
38514 this.autoSizeTabs();
38519 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38521 beginUpdate : function(){
38522 this.updating = true;
38526 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38528 endUpdate : function(){
38529 this.updating = false;
38530 this.autoSizeTabs();
38534 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38536 autoSizeTabs : function()
38538 var count = this.items.length;
38539 var vcount = count - this.hiddenCount;
38542 this.stripEl.hide();
38544 this.stripEl.show();
38547 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38552 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38553 var availWidth = Math.floor(w / vcount);
38554 var b = this.stripBody;
38555 if(b.getWidth() > w){
38556 var tabs = this.items;
38557 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38558 if(availWidth < this.minTabWidth){
38559 /*if(!this.sleft){ // incomplete scrolling code
38560 this.createScrollButtons();
38563 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38566 if(this.currentTabWidth < this.preferredTabWidth){
38567 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38573 * Returns the number of tabs in this TabPanel.
38576 getCount : function(){
38577 return this.items.length;
38581 * Resizes all the tabs to the passed width
38582 * @param {Number} The new width
38584 setTabWidth : function(width){
38585 this.currentTabWidth = width;
38586 for(var i = 0, len = this.items.length; i < len; i++) {
38587 if(!this.items[i].isHidden()) {
38588 this.items[i].setWidth(width);
38594 * Destroys this TabPanel
38595 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38597 destroy : function(removeEl){
38598 Roo.EventManager.removeResizeListener(this.onResize, this);
38599 for(var i = 0, len = this.items.length; i < len; i++){
38600 this.items[i].purgeListeners();
38602 if(removeEl === true){
38603 this.el.update("");
38608 createStrip : function(container)
38610 var strip = document.createElement("nav");
38611 strip.className = Roo.bootstrap.version == 4 ?
38612 "navbar-light bg-light" :
38613 "navbar navbar-default"; //"x-tabs-wrap";
38614 container.appendChild(strip);
38618 createStripList : function(strip)
38620 // div wrapper for retard IE
38621 // returns the "tr" element.
38622 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38623 //'<div class="x-tabs-strip-wrap">'+
38624 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38625 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38626 return strip.firstChild; //.firstChild.firstChild.firstChild;
38628 createBody : function(container)
38630 var body = document.createElement("div");
38631 Roo.id(body, "tab-body");
38632 //Roo.fly(body).addClass("x-tabs-body");
38633 Roo.fly(body).addClass("tab-content");
38634 container.appendChild(body);
38637 createItemBody :function(bodyEl, id){
38638 var body = Roo.getDom(id);
38640 body = document.createElement("div");
38643 //Roo.fly(body).addClass("x-tabs-item-body");
38644 Roo.fly(body).addClass("tab-pane");
38645 bodyEl.insertBefore(body, bodyEl.firstChild);
38649 createStripElements : function(stripEl, text, closable, tpl)
38651 var td = document.createElement("li"); // was td..
38652 td.className = 'nav-item';
38654 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38657 stripEl.appendChild(td);
38659 td.className = "x-tabs-closable";
38660 if(!this.closeTpl){
38661 this.closeTpl = new Roo.Template(
38662 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38663 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38664 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38667 var el = this.closeTpl.overwrite(td, {"text": text});
38668 var close = el.getElementsByTagName("div")[0];
38669 var inner = el.getElementsByTagName("em")[0];
38670 return {"el": el, "close": close, "inner": inner};
38673 // not sure what this is..
38674 // if(!this.tabTpl){
38675 //this.tabTpl = new Roo.Template(
38676 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38677 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38679 // this.tabTpl = new Roo.Template(
38680 // '<a href="#">' +
38681 // '<span unselectable="on"' +
38682 // (this.disableTooltips ? '' : ' title="{text}"') +
38683 // ' >{text}</span></a>'
38689 var template = tpl || this.tabTpl || false;
38692 template = new Roo.Template(
38693 Roo.bootstrap.version == 4 ?
38695 '<a class="nav-link" href="#" unselectable="on"' +
38696 (this.disableTooltips ? '' : ' title="{text}"') +
38699 '<a class="nav-link" href="#">' +
38700 '<span unselectable="on"' +
38701 (this.disableTooltips ? '' : ' title="{text}"') +
38702 ' >{text}</span></a>'
38707 switch (typeof(template)) {
38711 template = new Roo.Template(template);
38717 var el = template.overwrite(td, {"text": text});
38719 var inner = el.getElementsByTagName("span")[0];
38721 return {"el": el, "inner": inner};
38729 * @class Roo.TabPanelItem
38730 * @extends Roo.util.Observable
38731 * Represents an individual item (tab plus body) in a TabPanel.
38732 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38733 * @param {String} id The id of this TabPanelItem
38734 * @param {String} text The text for the tab of this TabPanelItem
38735 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38737 Roo.bootstrap.panel.TabItem = function(config){
38739 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38740 * @type Roo.TabPanel
38742 this.tabPanel = config.panel;
38744 * The id for this TabPanelItem
38747 this.id = config.id;
38749 this.disabled = false;
38751 this.text = config.text;
38753 this.loaded = false;
38754 this.closable = config.closable;
38757 * The body element for this TabPanelItem.
38758 * @type Roo.Element
38760 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38761 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38762 this.bodyEl.setStyle("display", "block");
38763 this.bodyEl.setStyle("zoom", "1");
38764 //this.hideAction();
38766 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38768 this.el = Roo.get(els.el);
38769 this.inner = Roo.get(els.inner, true);
38770 this.textEl = Roo.bootstrap.version == 4 ?
38771 this.el : Roo.get(this.el.dom.firstChild, true);
38773 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38774 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38777 // this.el.on("mousedown", this.onTabMouseDown, this);
38778 this.el.on("click", this.onTabClick, this);
38780 if(config.closable){
38781 var c = Roo.get(els.close, true);
38782 c.dom.title = this.closeText;
38783 c.addClassOnOver("close-over");
38784 c.on("click", this.closeClick, this);
38790 * Fires when this tab becomes the active tab.
38791 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38792 * @param {Roo.TabPanelItem} this
38796 * @event beforeclose
38797 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38798 * @param {Roo.TabPanelItem} this
38799 * @param {Object} e Set cancel to true on this object to cancel the close.
38801 "beforeclose": true,
38804 * Fires when this tab is closed.
38805 * @param {Roo.TabPanelItem} this
38809 * @event deactivate
38810 * Fires when this tab is no longer the active tab.
38811 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38812 * @param {Roo.TabPanelItem} this
38814 "deactivate" : true
38816 this.hidden = false;
38818 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38821 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38823 purgeListeners : function(){
38824 Roo.util.Observable.prototype.purgeListeners.call(this);
38825 this.el.removeAllListeners();
38828 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38831 this.status_node.addClass("active");
38834 this.tabPanel.stripWrap.repaint();
38836 this.fireEvent("activate", this.tabPanel, this);
38840 * Returns true if this tab is the active tab.
38841 * @return {Boolean}
38843 isActive : function(){
38844 return this.tabPanel.getActiveTab() == this;
38848 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38851 this.status_node.removeClass("active");
38853 this.fireEvent("deactivate", this.tabPanel, this);
38856 hideAction : function(){
38857 this.bodyEl.hide();
38858 this.bodyEl.setStyle("position", "absolute");
38859 this.bodyEl.setLeft("-20000px");
38860 this.bodyEl.setTop("-20000px");
38863 showAction : function(){
38864 this.bodyEl.setStyle("position", "relative");
38865 this.bodyEl.setTop("");
38866 this.bodyEl.setLeft("");
38867 this.bodyEl.show();
38871 * Set the tooltip for the tab.
38872 * @param {String} tooltip The tab's tooltip
38874 setTooltip : function(text){
38875 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38876 this.textEl.dom.qtip = text;
38877 this.textEl.dom.removeAttribute('title');
38879 this.textEl.dom.title = text;
38883 onTabClick : function(e){
38884 e.preventDefault();
38885 this.tabPanel.activate(this.id);
38888 onTabMouseDown : function(e){
38889 e.preventDefault();
38890 this.tabPanel.activate(this.id);
38893 getWidth : function(){
38894 return this.inner.getWidth();
38897 setWidth : function(width){
38898 var iwidth = width - this.linode.getPadding("lr");
38899 this.inner.setWidth(iwidth);
38900 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38901 this.linode.setWidth(width);
38905 * Show or hide the tab
38906 * @param {Boolean} hidden True to hide or false to show.
38908 setHidden : function(hidden){
38909 this.hidden = hidden;
38910 this.linode.setStyle("display", hidden ? "none" : "");
38914 * Returns true if this tab is "hidden"
38915 * @return {Boolean}
38917 isHidden : function(){
38918 return this.hidden;
38922 * Returns the text for this tab
38925 getText : function(){
38929 autoSize : function(){
38930 //this.el.beginMeasure();
38931 this.textEl.setWidth(1);
38933 * #2804 [new] Tabs in Roojs
38934 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38936 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38937 //this.el.endMeasure();
38941 * Sets the text for the tab (Note: this also sets the tooltip text)
38942 * @param {String} text The tab's text and tooltip
38944 setText : function(text){
38946 this.textEl.update(text);
38947 this.setTooltip(text);
38948 //if(!this.tabPanel.resizeTabs){
38949 // this.autoSize();
38953 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38955 activate : function(){
38956 this.tabPanel.activate(this.id);
38960 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38962 disable : function(){
38963 if(this.tabPanel.active != this){
38964 this.disabled = true;
38965 this.status_node.addClass("disabled");
38970 * Enables this TabPanelItem if it was previously disabled.
38972 enable : function(){
38973 this.disabled = false;
38974 this.status_node.removeClass("disabled");
38978 * Sets the content for this TabPanelItem.
38979 * @param {String} content The content
38980 * @param {Boolean} loadScripts true to look for and load scripts
38982 setContent : function(content, loadScripts){
38983 this.bodyEl.update(content, loadScripts);
38987 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38988 * @return {Roo.UpdateManager} The UpdateManager
38990 getUpdateManager : function(){
38991 return this.bodyEl.getUpdateManager();
38995 * Set a URL to be used to load the content for this TabPanelItem.
38996 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38997 * @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)
38998 * @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)
38999 * @return {Roo.UpdateManager} The UpdateManager
39001 setUrl : function(url, params, loadOnce){
39002 if(this.refreshDelegate){
39003 this.un('activate', this.refreshDelegate);
39005 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39006 this.on("activate", this.refreshDelegate);
39007 return this.bodyEl.getUpdateManager();
39011 _handleRefresh : function(url, params, loadOnce){
39012 if(!loadOnce || !this.loaded){
39013 var updater = this.bodyEl.getUpdateManager();
39014 updater.update(url, params, this._setLoaded.createDelegate(this));
39019 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39020 * Will fail silently if the setUrl method has not been called.
39021 * This does not activate the panel, just updates its content.
39023 refresh : function(){
39024 if(this.refreshDelegate){
39025 this.loaded = false;
39026 this.refreshDelegate();
39031 _setLoaded : function(){
39032 this.loaded = true;
39036 closeClick : function(e){
39039 this.fireEvent("beforeclose", this, o);
39040 if(o.cancel !== true){
39041 this.tabPanel.removeTab(this.id);
39045 * The text displayed in the tooltip for the close icon.
39048 closeText : "Close this tab"
39051 * This script refer to:
39052 * Title: International Telephone Input
39053 * Author: Jack O'Connor
39054 * Code version: v12.1.12
39055 * Availability: https://github.com/jackocnr/intl-tel-input.git
39058 Roo.bootstrap.PhoneInputData = function() {
39061 "Afghanistan (افغانستان)",
39066 "Albania (Shqipëri)",
39071 "Algeria (الجزائر)",
39096 "Antigua and Barbuda",
39106 "Armenia (Հայաստան)",
39122 "Austria (Österreich)",
39127 "Azerbaijan (Azərbaycan)",
39137 "Bahrain (البحرين)",
39142 "Bangladesh (বাংলাদেশ)",
39152 "Belarus (Беларусь)",
39157 "Belgium (België)",
39187 "Bosnia and Herzegovina (Босна и Херцеговина)",
39202 "British Indian Ocean Territory",
39207 "British Virgin Islands",
39217 "Bulgaria (България)",
39227 "Burundi (Uburundi)",
39232 "Cambodia (កម្ពុជា)",
39237 "Cameroon (Cameroun)",
39246 ["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"]
39249 "Cape Verde (Kabu Verdi)",
39254 "Caribbean Netherlands",
39265 "Central African Republic (République centrafricaine)",
39285 "Christmas Island",
39291 "Cocos (Keeling) Islands",
39302 "Comoros (جزر القمر)",
39307 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39312 "Congo (Republic) (Congo-Brazzaville)",
39332 "Croatia (Hrvatska)",
39353 "Czech Republic (Česká republika)",
39358 "Denmark (Danmark)",
39373 "Dominican Republic (República Dominicana)",
39377 ["809", "829", "849"]
39395 "Equatorial Guinea (Guinea Ecuatorial)",
39415 "Falkland Islands (Islas Malvinas)",
39420 "Faroe Islands (Føroyar)",
39441 "French Guiana (Guyane française)",
39446 "French Polynesia (Polynésie française)",
39461 "Georgia (საქართველო)",
39466 "Germany (Deutschland)",
39486 "Greenland (Kalaallit Nunaat)",
39523 "Guinea-Bissau (Guiné Bissau)",
39548 "Hungary (Magyarország)",
39553 "Iceland (Ísland)",
39573 "Iraq (العراق)",
39589 "Israel (ישראל)",
39616 "Jordan (الأردن)",
39621 "Kazakhstan (Казахстан)",
39642 "Kuwait (الكويت)",
39647 "Kyrgyzstan (Кыргызстан)",
39657 "Latvia (Latvija)",
39662 "Lebanon (لبنان)",
39677 "Libya (ليبيا)",
39687 "Lithuania (Lietuva)",
39702 "Macedonia (FYROM) (Македонија)",
39707 "Madagascar (Madagasikara)",
39737 "Marshall Islands",
39747 "Mauritania (موريتانيا)",
39752 "Mauritius (Moris)",
39773 "Moldova (Republica Moldova)",
39783 "Mongolia (Монгол)",
39788 "Montenegro (Crna Gora)",
39798 "Morocco (المغرب)",
39804 "Mozambique (Moçambique)",
39809 "Myanmar (Burma) (မြန်မာ)",
39814 "Namibia (Namibië)",
39829 "Netherlands (Nederland)",
39834 "New Caledonia (Nouvelle-Calédonie)",
39869 "North Korea (조선 민주주의 인민 공화국)",
39874 "Northern Mariana Islands",
39890 "Pakistan (پاکستان)",
39900 "Palestine (فلسطين)",
39910 "Papua New Guinea",
39952 "Réunion (La Réunion)",
39958 "Romania (România)",
39974 "Saint Barthélemy",
39985 "Saint Kitts and Nevis",
39995 "Saint Martin (Saint-Martin (partie française))",
40001 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
40006 "Saint Vincent and the Grenadines",
40021 "São Tomé and Príncipe (São Tomé e Príncipe)",
40026 "Saudi Arabia (المملكة العربية السعودية)",
40031 "Senegal (Sénégal)",
40061 "Slovakia (Slovensko)",
40066 "Slovenia (Slovenija)",
40076 "Somalia (Soomaaliya)",
40086 "South Korea (대한민국)",
40091 "South Sudan (جنوب السودان)",
40101 "Sri Lanka (ශ්රී ලංකාව)",
40106 "Sudan (السودان)",
40116 "Svalbard and Jan Mayen",
40127 "Sweden (Sverige)",
40132 "Switzerland (Schweiz)",
40137 "Syria (سوريا)",
40182 "Trinidad and Tobago",
40187 "Tunisia (تونس)",
40192 "Turkey (Türkiye)",
40202 "Turks and Caicos Islands",
40212 "U.S. Virgin Islands",
40222 "Ukraine (Україна)",
40227 "United Arab Emirates (الإمارات العربية المتحدة)",
40249 "Uzbekistan (Oʻzbekiston)",
40259 "Vatican City (Città del Vaticano)",
40270 "Vietnam (Việt Nam)",
40275 "Wallis and Futuna (Wallis-et-Futuna)",
40280 "Western Sahara (الصحراء الغربية)",
40286 "Yemen (اليمن)",
40310 * This script refer to:
40311 * Title: International Telephone Input
40312 * Author: Jack O'Connor
40313 * Code version: v12.1.12
40314 * Availability: https://github.com/jackocnr/intl-tel-input.git
40318 * @class Roo.bootstrap.PhoneInput
40319 * @extends Roo.bootstrap.TriggerField
40320 * An input with International dial-code selection
40322 * @cfg {String} defaultDialCode default '+852'
40323 * @cfg {Array} preferedCountries default []
40326 * Create a new PhoneInput.
40327 * @param {Object} config Configuration options
40330 Roo.bootstrap.PhoneInput = function(config) {
40331 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40334 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40336 listWidth: undefined,
40338 selectedClass: 'active',
40340 invalidClass : "has-warning",
40342 validClass: 'has-success',
40344 allowed: '0123456789',
40349 * @cfg {String} defaultDialCode The default dial code when initializing the input
40351 defaultDialCode: '+852',
40354 * @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
40356 preferedCountries: false,
40358 getAutoCreate : function()
40360 var data = Roo.bootstrap.PhoneInputData();
40361 var align = this.labelAlign || this.parentLabelAlign();
40364 this.allCountries = [];
40365 this.dialCodeMapping = [];
40367 for (var i = 0; i < data.length; i++) {
40369 this.allCountries[i] = {
40373 priority: c[3] || 0,
40374 areaCodes: c[4] || null
40376 this.dialCodeMapping[c[2]] = {
40379 priority: c[3] || 0,
40380 areaCodes: c[4] || null
40392 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40393 maxlength: this.max_length,
40394 cls : 'form-control tel-input',
40395 autocomplete: 'new-password'
40398 var hiddenInput = {
40401 cls: 'hidden-tel-input'
40405 hiddenInput.name = this.name;
40408 if (this.disabled) {
40409 input.disabled = true;
40412 var flag_container = {
40429 cls: this.hasFeedback ? 'has-feedback' : '',
40435 cls: 'dial-code-holder',
40442 cls: 'roo-select2-container input-group',
40449 if (this.fieldLabel.length) {
40452 tooltip: 'This field is required'
40458 cls: 'control-label',
40464 html: this.fieldLabel
40467 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40473 if(this.indicatorpos == 'right') {
40474 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40481 if(align == 'left') {
40489 if(this.labelWidth > 12){
40490 label.style = "width: " + this.labelWidth + 'px';
40492 if(this.labelWidth < 13 && this.labelmd == 0){
40493 this.labelmd = this.labelWidth;
40495 if(this.labellg > 0){
40496 label.cls += ' col-lg-' + this.labellg;
40497 input.cls += ' col-lg-' + (12 - this.labellg);
40499 if(this.labelmd > 0){
40500 label.cls += ' col-md-' + this.labelmd;
40501 container.cls += ' col-md-' + (12 - this.labelmd);
40503 if(this.labelsm > 0){
40504 label.cls += ' col-sm-' + this.labelsm;
40505 container.cls += ' col-sm-' + (12 - this.labelsm);
40507 if(this.labelxs > 0){
40508 label.cls += ' col-xs-' + this.labelxs;
40509 container.cls += ' col-xs-' + (12 - this.labelxs);
40519 var settings = this;
40521 ['xs','sm','md','lg'].map(function(size){
40522 if (settings[size]) {
40523 cfg.cls += ' col-' + size + '-' + settings[size];
40527 this.store = new Roo.data.Store({
40528 proxy : new Roo.data.MemoryProxy({}),
40529 reader : new Roo.data.JsonReader({
40540 'name' : 'dialCode',
40544 'name' : 'priority',
40548 'name' : 'areaCodes',
40555 if(!this.preferedCountries) {
40556 this.preferedCountries = [
40563 var p = this.preferedCountries.reverse();
40566 for (var i = 0; i < p.length; i++) {
40567 for (var j = 0; j < this.allCountries.length; j++) {
40568 if(this.allCountries[j].iso2 == p[i]) {
40569 var t = this.allCountries[j];
40570 this.allCountries.splice(j,1);
40571 this.allCountries.unshift(t);
40577 this.store.proxy.data = {
40579 data: this.allCountries
40585 initEvents : function()
40588 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40590 this.indicator = this.indicatorEl();
40591 this.flag = this.flagEl();
40592 this.dialCodeHolder = this.dialCodeHolderEl();
40594 this.trigger = this.el.select('div.flag-box',true).first();
40595 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40600 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40601 _this.list.setWidth(lw);
40604 this.list.on('mouseover', this.onViewOver, this);
40605 this.list.on('mousemove', this.onViewMove, this);
40606 this.inputEl().on("keyup", this.onKeyUp, this);
40607 this.inputEl().on("keypress", this.onKeyPress, this);
40609 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40611 this.view = new Roo.View(this.list, this.tpl, {
40612 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40615 this.view.on('click', this.onViewClick, this);
40616 this.setValue(this.defaultDialCode);
40619 onTriggerClick : function(e)
40621 Roo.log('trigger click');
40626 if(this.isExpanded()){
40628 this.hasFocus = false;
40630 this.store.load({});
40631 this.hasFocus = true;
40636 isExpanded : function()
40638 return this.list.isVisible();
40641 collapse : function()
40643 if(!this.isExpanded()){
40647 Roo.get(document).un('mousedown', this.collapseIf, this);
40648 Roo.get(document).un('mousewheel', this.collapseIf, this);
40649 this.fireEvent('collapse', this);
40653 expand : function()
40657 if(this.isExpanded() || !this.hasFocus){
40661 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40662 this.list.setWidth(lw);
40665 this.restrictHeight();
40667 Roo.get(document).on('mousedown', this.collapseIf, this);
40668 Roo.get(document).on('mousewheel', this.collapseIf, this);
40670 this.fireEvent('expand', this);
40673 restrictHeight : function()
40675 this.list.alignTo(this.inputEl(), this.listAlign);
40676 this.list.alignTo(this.inputEl(), this.listAlign);
40679 onViewOver : function(e, t)
40681 if(this.inKeyMode){
40684 var item = this.view.findItemFromChild(t);
40687 var index = this.view.indexOf(item);
40688 this.select(index, false);
40693 onViewClick : function(view, doFocus, el, e)
40695 var index = this.view.getSelectedIndexes()[0];
40697 var r = this.store.getAt(index);
40700 this.onSelect(r, index);
40702 if(doFocus !== false && !this.blockFocus){
40703 this.inputEl().focus();
40707 onViewMove : function(e, t)
40709 this.inKeyMode = false;
40712 select : function(index, scrollIntoView)
40714 this.selectedIndex = index;
40715 this.view.select(index);
40716 if(scrollIntoView !== false){
40717 var el = this.view.getNode(index);
40719 this.list.scrollChildIntoView(el, false);
40724 createList : function()
40726 this.list = Roo.get(document.body).createChild({
40728 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40729 style: 'display:none'
40732 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40735 collapseIf : function(e)
40737 var in_combo = e.within(this.el);
40738 var in_list = e.within(this.list);
40739 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40741 if (in_combo || in_list || is_list) {
40747 onSelect : function(record, index)
40749 if(this.fireEvent('beforeselect', this, record, index) !== false){
40751 this.setFlagClass(record.data.iso2);
40752 this.setDialCode(record.data.dialCode);
40753 this.hasFocus = false;
40755 this.fireEvent('select', this, record, index);
40759 flagEl : function()
40761 var flag = this.el.select('div.flag',true).first();
40768 dialCodeHolderEl : function()
40770 var d = this.el.select('input.dial-code-holder',true).first();
40777 setDialCode : function(v)
40779 this.dialCodeHolder.dom.value = '+'+v;
40782 setFlagClass : function(n)
40784 this.flag.dom.className = 'flag '+n;
40787 getValue : function()
40789 var v = this.inputEl().getValue();
40790 if(this.dialCodeHolder) {
40791 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40796 setValue : function(v)
40798 var d = this.getDialCode(v);
40800 //invalid dial code
40801 if(v.length == 0 || !d || d.length == 0) {
40803 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40804 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40810 this.setFlagClass(this.dialCodeMapping[d].iso2);
40811 this.setDialCode(d);
40812 this.inputEl().dom.value = v.replace('+'+d,'');
40813 this.hiddenEl().dom.value = this.getValue();
40818 getDialCode : function(v)
40822 if (v.length == 0) {
40823 return this.dialCodeHolder.dom.value;
40827 if (v.charAt(0) != "+") {
40830 var numericChars = "";
40831 for (var i = 1; i < v.length; i++) {
40832 var c = v.charAt(i);
40835 if (this.dialCodeMapping[numericChars]) {
40836 dialCode = v.substr(1, i);
40838 if (numericChars.length == 4) {
40848 this.setValue(this.defaultDialCode);
40852 hiddenEl : function()
40854 return this.el.select('input.hidden-tel-input',true).first();
40857 // after setting val
40858 onKeyUp : function(e){
40859 this.setValue(this.getValue());
40862 onKeyPress : function(e){
40863 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40870 * @class Roo.bootstrap.MoneyField
40871 * @extends Roo.bootstrap.ComboBox
40872 * Bootstrap MoneyField class
40875 * Create a new MoneyField.
40876 * @param {Object} config Configuration options
40879 Roo.bootstrap.MoneyField = function(config) {
40881 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40885 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40888 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40890 allowDecimals : true,
40892 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40894 decimalSeparator : ".",
40896 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40898 decimalPrecision : 0,
40900 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40902 allowNegative : true,
40904 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40908 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40910 minValue : Number.NEGATIVE_INFINITY,
40912 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40914 maxValue : Number.MAX_VALUE,
40916 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40918 minText : "The minimum value for this field is {0}",
40920 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40922 maxText : "The maximum value for this field is {0}",
40924 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40925 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40927 nanText : "{0} is not a valid number",
40929 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40933 * @cfg {String} defaults currency of the MoneyField
40934 * value should be in lkey
40936 defaultCurrency : false,
40938 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40940 thousandsDelimiter : false,
40942 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40953 getAutoCreate : function()
40955 var align = this.labelAlign || this.parentLabelAlign();
40967 cls : 'form-control roo-money-amount-input',
40968 autocomplete: 'new-password'
40971 var hiddenInput = {
40975 cls: 'hidden-number-input'
40978 if(this.max_length) {
40979 input.maxlength = this.max_length;
40983 hiddenInput.name = this.name;
40986 if (this.disabled) {
40987 input.disabled = true;
40990 var clg = 12 - this.inputlg;
40991 var cmd = 12 - this.inputmd;
40992 var csm = 12 - this.inputsm;
40993 var cxs = 12 - this.inputxs;
40997 cls : 'row roo-money-field',
41001 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
41005 cls: 'roo-select2-container input-group',
41009 cls : 'form-control roo-money-currency-input',
41010 autocomplete: 'new-password',
41012 name : this.currencyName
41016 cls : 'input-group-addon',
41030 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41034 cls: this.hasFeedback ? 'has-feedback' : '',
41045 if (this.fieldLabel.length) {
41048 tooltip: 'This field is required'
41054 cls: 'control-label',
41060 html: this.fieldLabel
41063 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41069 if(this.indicatorpos == 'right') {
41070 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41077 if(align == 'left') {
41085 if(this.labelWidth > 12){
41086 label.style = "width: " + this.labelWidth + 'px';
41088 if(this.labelWidth < 13 && this.labelmd == 0){
41089 this.labelmd = this.labelWidth;
41091 if(this.labellg > 0){
41092 label.cls += ' col-lg-' + this.labellg;
41093 input.cls += ' col-lg-' + (12 - this.labellg);
41095 if(this.labelmd > 0){
41096 label.cls += ' col-md-' + this.labelmd;
41097 container.cls += ' col-md-' + (12 - this.labelmd);
41099 if(this.labelsm > 0){
41100 label.cls += ' col-sm-' + this.labelsm;
41101 container.cls += ' col-sm-' + (12 - this.labelsm);
41103 if(this.labelxs > 0){
41104 label.cls += ' col-xs-' + this.labelxs;
41105 container.cls += ' col-xs-' + (12 - this.labelxs);
41116 var settings = this;
41118 ['xs','sm','md','lg'].map(function(size){
41119 if (settings[size]) {
41120 cfg.cls += ' col-' + size + '-' + settings[size];
41127 initEvents : function()
41129 this.indicator = this.indicatorEl();
41131 this.initCurrencyEvent();
41133 this.initNumberEvent();
41136 initCurrencyEvent : function()
41139 throw "can not find store for combo";
41142 this.store = Roo.factory(this.store, Roo.data);
41143 this.store.parent = this;
41147 this.triggerEl = this.el.select('.input-group-addon', true).first();
41149 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41154 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41155 _this.list.setWidth(lw);
41158 this.list.on('mouseover', this.onViewOver, this);
41159 this.list.on('mousemove', this.onViewMove, this);
41160 this.list.on('scroll', this.onViewScroll, this);
41163 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41166 this.view = new Roo.View(this.list, this.tpl, {
41167 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41170 this.view.on('click', this.onViewClick, this);
41172 this.store.on('beforeload', this.onBeforeLoad, this);
41173 this.store.on('load', this.onLoad, this);
41174 this.store.on('loadexception', this.onLoadException, this);
41176 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41177 "up" : function(e){
41178 this.inKeyMode = true;
41182 "down" : function(e){
41183 if(!this.isExpanded()){
41184 this.onTriggerClick();
41186 this.inKeyMode = true;
41191 "enter" : function(e){
41194 if(this.fireEvent("specialkey", this, e)){
41195 this.onViewClick(false);
41201 "esc" : function(e){
41205 "tab" : function(e){
41208 if(this.fireEvent("specialkey", this, e)){
41209 this.onViewClick(false);
41217 doRelay : function(foo, bar, hname){
41218 if(hname == 'down' || this.scope.isExpanded()){
41219 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41227 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41231 initNumberEvent : function(e)
41233 this.inputEl().on("keydown" , this.fireKey, this);
41234 this.inputEl().on("focus", this.onFocus, this);
41235 this.inputEl().on("blur", this.onBlur, this);
41237 this.inputEl().relayEvent('keyup', this);
41239 if(this.indicator){
41240 this.indicator.addClass('invisible');
41243 this.originalValue = this.getValue();
41245 if(this.validationEvent == 'keyup'){
41246 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41247 this.inputEl().on('keyup', this.filterValidation, this);
41249 else if(this.validationEvent !== false){
41250 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41253 if(this.selectOnFocus){
41254 this.on("focus", this.preFocus, this);
41257 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41258 this.inputEl().on("keypress", this.filterKeys, this);
41260 this.inputEl().relayEvent('keypress', this);
41263 var allowed = "0123456789";
41265 if(this.allowDecimals){
41266 allowed += this.decimalSeparator;
41269 if(this.allowNegative){
41273 if(this.thousandsDelimiter) {
41277 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41279 var keyPress = function(e){
41281 var k = e.getKey();
41283 var c = e.getCharCode();
41286 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41287 allowed.indexOf(String.fromCharCode(c)) === -1
41293 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41297 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41302 this.inputEl().on("keypress", keyPress, this);
41306 onTriggerClick : function(e)
41313 this.loadNext = false;
41315 if(this.isExpanded()){
41320 this.hasFocus = true;
41322 if(this.triggerAction == 'all') {
41323 this.doQuery(this.allQuery, true);
41327 this.doQuery(this.getRawValue());
41330 getCurrency : function()
41332 var v = this.currencyEl().getValue();
41337 restrictHeight : function()
41339 this.list.alignTo(this.currencyEl(), this.listAlign);
41340 this.list.alignTo(this.currencyEl(), this.listAlign);
41343 onViewClick : function(view, doFocus, el, e)
41345 var index = this.view.getSelectedIndexes()[0];
41347 var r = this.store.getAt(index);
41350 this.onSelect(r, index);
41354 onSelect : function(record, index){
41356 if(this.fireEvent('beforeselect', this, record, index) !== false){
41358 this.setFromCurrencyData(index > -1 ? record.data : false);
41362 this.fireEvent('select', this, record, index);
41366 setFromCurrencyData : function(o)
41370 this.lastCurrency = o;
41372 if (this.currencyField) {
41373 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41375 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41378 this.lastSelectionText = currency;
41380 //setting default currency
41381 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41382 this.setCurrency(this.defaultCurrency);
41386 this.setCurrency(currency);
41389 setFromData : function(o)
41393 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41395 this.setFromCurrencyData(c);
41400 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41402 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41405 this.setValue(value);
41409 setCurrency : function(v)
41411 this.currencyValue = v;
41414 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41419 setValue : function(v)
41421 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41427 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41429 this.inputEl().dom.value = (v == '') ? '' :
41430 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41432 if(!this.allowZero && v === '0') {
41433 this.hiddenEl().dom.value = '';
41434 this.inputEl().dom.value = '';
41441 getRawValue : function()
41443 var v = this.inputEl().getValue();
41448 getValue : function()
41450 return this.fixPrecision(this.parseValue(this.getRawValue()));
41453 parseValue : function(value)
41455 if(this.thousandsDelimiter) {
41457 r = new RegExp(",", "g");
41458 value = value.replace(r, "");
41461 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41462 return isNaN(value) ? '' : value;
41466 fixPrecision : function(value)
41468 if(this.thousandsDelimiter) {
41470 r = new RegExp(",", "g");
41471 value = value.replace(r, "");
41474 var nan = isNaN(value);
41476 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41477 return nan ? '' : value;
41479 return parseFloat(value).toFixed(this.decimalPrecision);
41482 decimalPrecisionFcn : function(v)
41484 return Math.floor(v);
41487 validateValue : function(value)
41489 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41493 var num = this.parseValue(value);
41496 this.markInvalid(String.format(this.nanText, value));
41500 if(num < this.minValue){
41501 this.markInvalid(String.format(this.minText, this.minValue));
41505 if(num > this.maxValue){
41506 this.markInvalid(String.format(this.maxText, this.maxValue));
41513 validate : function()
41515 if(this.disabled || this.allowBlank){
41520 var currency = this.getCurrency();
41522 if(this.validateValue(this.getRawValue()) && currency.length){
41527 this.markInvalid();
41531 getName: function()
41536 beforeBlur : function()
41542 var v = this.parseValue(this.getRawValue());
41549 onBlur : function()
41553 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41554 //this.el.removeClass(this.focusClass);
41557 this.hasFocus = false;
41559 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41563 var v = this.getValue();
41565 if(String(v) !== String(this.startValue)){
41566 this.fireEvent('change', this, v, this.startValue);
41569 this.fireEvent("blur", this);
41572 inputEl : function()
41574 return this.el.select('.roo-money-amount-input', true).first();
41577 currencyEl : function()
41579 return this.el.select('.roo-money-currency-input', true).first();
41582 hiddenEl : function()
41584 return this.el.select('input.hidden-number-input',true).first();
41588 * @class Roo.bootstrap.BezierSignature
41589 * @extends Roo.bootstrap.Component
41590 * Bootstrap BezierSignature class
41591 * This script refer to:
41592 * Title: Signature Pad
41594 * Availability: https://github.com/szimek/signature_pad
41597 * Create a new BezierSignature
41598 * @param {Object} config The config object
41601 Roo.bootstrap.BezierSignature = function(config){
41602 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41608 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41615 mouse_btn_down: true,
41618 * @cfg {int} canvas height
41620 canvas_height: '200px',
41623 * @cfg {float|function} Radius of a single dot.
41628 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41633 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41638 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41643 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41648 * @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.
41650 bg_color: 'rgba(0, 0, 0, 0)',
41653 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41655 dot_color: 'black',
41658 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41660 velocity_filter_weight: 0.7,
41663 * @cfg {function} Callback when stroke begin.
41668 * @cfg {function} Callback when stroke end.
41672 getAutoCreate : function()
41674 var cls = 'roo-signature column';
41677 cls += ' ' + this.cls;
41687 for(var i = 0; i < col_sizes.length; i++) {
41688 if(this[col_sizes[i]]) {
41689 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41699 cls: 'roo-signature-body',
41703 cls: 'roo-signature-body-canvas',
41704 height: this.canvas_height,
41705 width: this.canvas_width
41712 style: 'display: none'
41720 initEvents: function()
41722 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41724 var canvas = this.canvasEl();
41726 // mouse && touch event swapping...
41727 canvas.dom.style.touchAction = 'none';
41728 canvas.dom.style.msTouchAction = 'none';
41730 this.mouse_btn_down = false;
41731 canvas.on('mousedown', this._handleMouseDown, this);
41732 canvas.on('mousemove', this._handleMouseMove, this);
41733 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41735 if (window.PointerEvent) {
41736 canvas.on('pointerdown', this._handleMouseDown, this);
41737 canvas.on('pointermove', this._handleMouseMove, this);
41738 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41741 if ('ontouchstart' in window) {
41742 canvas.on('touchstart', this._handleTouchStart, this);
41743 canvas.on('touchmove', this._handleTouchMove, this);
41744 canvas.on('touchend', this._handleTouchEnd, this);
41747 Roo.EventManager.onWindowResize(this.resize, this, true);
41749 // file input event
41750 this.fileEl().on('change', this.uploadImage, this);
41757 resize: function(){
41759 var canvas = this.canvasEl().dom;
41760 var ctx = this.canvasElCtx();
41761 var img_data = false;
41763 if(canvas.width > 0) {
41764 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41766 // setting canvas width will clean img data
41769 var style = window.getComputedStyle ?
41770 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41772 var padding_left = parseInt(style.paddingLeft) || 0;
41773 var padding_right = parseInt(style.paddingRight) || 0;
41775 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41778 ctx.putImageData(img_data, 0, 0);
41782 _handleMouseDown: function(e)
41784 if (e.browserEvent.which === 1) {
41785 this.mouse_btn_down = true;
41786 this.strokeBegin(e);
41790 _handleMouseMove: function (e)
41792 if (this.mouse_btn_down) {
41793 this.strokeMoveUpdate(e);
41797 _handleMouseUp: function (e)
41799 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41800 this.mouse_btn_down = false;
41805 _handleTouchStart: function (e) {
41807 e.preventDefault();
41808 if (e.browserEvent.targetTouches.length === 1) {
41809 // var touch = e.browserEvent.changedTouches[0];
41810 // this.strokeBegin(touch);
41812 this.strokeBegin(e); // assume e catching the correct xy...
41816 _handleTouchMove: function (e) {
41817 e.preventDefault();
41818 // var touch = event.targetTouches[0];
41819 // _this._strokeMoveUpdate(touch);
41820 this.strokeMoveUpdate(e);
41823 _handleTouchEnd: function (e) {
41824 var wasCanvasTouched = e.target === this.canvasEl().dom;
41825 if (wasCanvasTouched) {
41826 e.preventDefault();
41827 // var touch = event.changedTouches[0];
41828 // _this._strokeEnd(touch);
41833 reset: function () {
41834 this._lastPoints = [];
41835 this._lastVelocity = 0;
41836 this._lastWidth = (this.min_width + this.max_width) / 2;
41837 this.canvasElCtx().fillStyle = this.dot_color;
41840 strokeMoveUpdate: function(e)
41842 this.strokeUpdate(e);
41844 if (this.throttle) {
41845 this.throttleStroke(this.strokeUpdate, this.throttle);
41848 this.strokeUpdate(e);
41852 strokeBegin: function(e)
41854 var newPointGroup = {
41855 color: this.dot_color,
41859 if (typeof this.onBegin === 'function') {
41863 this.curve_data.push(newPointGroup);
41865 this.strokeUpdate(e);
41868 strokeUpdate: function(e)
41870 var rect = this.canvasEl().dom.getBoundingClientRect();
41871 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41872 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41873 var lastPoints = lastPointGroup.points;
41874 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41875 var isLastPointTooClose = lastPoint
41876 ? point.distanceTo(lastPoint) <= this.min_distance
41878 var color = lastPointGroup.color;
41879 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41880 var curve = this.addPoint(point);
41882 this.drawDot({color: color, point: point});
41885 this.drawCurve({color: color, curve: curve});
41895 strokeEnd: function(e)
41897 this.strokeUpdate(e);
41898 if (typeof this.onEnd === 'function') {
41903 addPoint: function (point) {
41904 var _lastPoints = this._lastPoints;
41905 _lastPoints.push(point);
41906 if (_lastPoints.length > 2) {
41907 if (_lastPoints.length === 3) {
41908 _lastPoints.unshift(_lastPoints[0]);
41910 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41911 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41912 _lastPoints.shift();
41918 calculateCurveWidths: function (startPoint, endPoint) {
41919 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41920 (1 - this.velocity_filter_weight) * this._lastVelocity;
41922 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41925 start: this._lastWidth
41928 this._lastVelocity = velocity;
41929 this._lastWidth = newWidth;
41933 drawDot: function (_a) {
41934 var color = _a.color, point = _a.point;
41935 var ctx = this.canvasElCtx();
41936 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41938 this.drawCurveSegment(point.x, point.y, width);
41940 ctx.fillStyle = color;
41944 drawCurve: function (_a) {
41945 var color = _a.color, curve = _a.curve;
41946 var ctx = this.canvasElCtx();
41947 var widthDelta = curve.endWidth - curve.startWidth;
41948 var drawSteps = Math.floor(curve.length()) * 2;
41950 ctx.fillStyle = color;
41951 for (var i = 0; i < drawSteps; i += 1) {
41952 var t = i / drawSteps;
41958 var x = uuu * curve.startPoint.x;
41959 x += 3 * uu * t * curve.control1.x;
41960 x += 3 * u * tt * curve.control2.x;
41961 x += ttt * curve.endPoint.x;
41962 var y = uuu * curve.startPoint.y;
41963 y += 3 * uu * t * curve.control1.y;
41964 y += 3 * u * tt * curve.control2.y;
41965 y += ttt * curve.endPoint.y;
41966 var width = curve.startWidth + ttt * widthDelta;
41967 this.drawCurveSegment(x, y, width);
41973 drawCurveSegment: function (x, y, width) {
41974 var ctx = this.canvasElCtx();
41976 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41977 this.is_empty = false;
41982 var ctx = this.canvasElCtx();
41983 var canvas = this.canvasEl().dom;
41984 ctx.fillStyle = this.bg_color;
41985 ctx.clearRect(0, 0, canvas.width, canvas.height);
41986 ctx.fillRect(0, 0, canvas.width, canvas.height);
41987 this.curve_data = [];
41989 this.is_empty = true;
41994 return this.el.select('input',true).first();
41997 canvasEl: function()
41999 return this.el.select('canvas',true).first();
42002 canvasElCtx: function()
42004 return this.el.select('canvas',true).first().dom.getContext('2d');
42007 getImage: function(type)
42009 if(this.is_empty) {
42014 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42017 drawFromImage: function(img_src)
42019 var img = new Image();
42021 img.onload = function(){
42022 this.canvasElCtx().drawImage(img, 0, 0);
42027 this.is_empty = false;
42030 selectImage: function()
42032 this.fileEl().dom.click();
42035 uploadImage: function(e)
42037 var reader = new FileReader();
42039 reader.onload = function(e){
42040 var img = new Image();
42041 img.onload = function(){
42043 this.canvasElCtx().drawImage(img, 0, 0);
42045 img.src = e.target.result;
42048 reader.readAsDataURL(e.target.files[0]);
42051 // Bezier Point Constructor
42052 Point: (function () {
42053 function Point(x, y, time) {
42056 this.time = time || Date.now();
42058 Point.prototype.distanceTo = function (start) {
42059 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42061 Point.prototype.equals = function (other) {
42062 return this.x === other.x && this.y === other.y && this.time === other.time;
42064 Point.prototype.velocityFrom = function (start) {
42065 return this.time !== start.time
42066 ? this.distanceTo(start) / (this.time - start.time)
42073 // Bezier Constructor
42074 Bezier: (function () {
42075 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42076 this.startPoint = startPoint;
42077 this.control2 = control2;
42078 this.control1 = control1;
42079 this.endPoint = endPoint;
42080 this.startWidth = startWidth;
42081 this.endWidth = endWidth;
42083 Bezier.fromPoints = function (points, widths, scope) {
42084 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42085 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42086 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42088 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42089 var dx1 = s1.x - s2.x;
42090 var dy1 = s1.y - s2.y;
42091 var dx2 = s2.x - s3.x;
42092 var dy2 = s2.y - s3.y;
42093 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42094 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42095 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42096 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42097 var dxm = m1.x - m2.x;
42098 var dym = m1.y - m2.y;
42099 var k = l2 / (l1 + l2);
42100 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42101 var tx = s2.x - cm.x;
42102 var ty = s2.y - cm.y;
42104 c1: new scope.Point(m1.x + tx, m1.y + ty),
42105 c2: new scope.Point(m2.x + tx, m2.y + ty)
42108 Bezier.prototype.length = function () {
42113 for (var i = 0; i <= steps; i += 1) {
42115 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42116 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42118 var xdiff = cx - px;
42119 var ydiff = cy - py;
42120 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42127 Bezier.prototype.point = function (t, start, c1, c2, end) {
42128 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42129 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42130 + (3.0 * c2 * (1.0 - t) * t * t)
42131 + (end * t * t * t);
42136 throttleStroke: function(fn, wait) {
42137 if (wait === void 0) { wait = 250; }
42139 var timeout = null;
42143 var later = function () {
42144 previous = Date.now();
42146 result = fn.apply(storedContext, storedArgs);
42148 storedContext = null;
42152 return function wrapper() {
42154 for (var _i = 0; _i < arguments.length; _i++) {
42155 args[_i] = arguments[_i];
42157 var now = Date.now();
42158 var remaining = wait - (now - previous);
42159 storedContext = this;
42161 if (remaining <= 0 || remaining > wait) {
42163 clearTimeout(timeout);
42167 result = fn.apply(storedContext, storedArgs);
42169 storedContext = null;
42173 else if (!timeout) {
42174 timeout = window.setTimeout(later, remaining);